在INotifyPropertyChanged上刷新值转换器

我知道这里有一些类似的话题,但我无法从他们那里得到任何答案。 我必须在我的Windows Phone 7应用程序中将网格背景更新为图像或颜色。 我使用我的值转换器,它工作正常,但我必须重新加载集合,以便更新颜色或图像。

 

转换器接收对象然后从中获取颜色和图像,这里是转换器

 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { People myC = value as People; string myImage = myC.Image; object result = myC.TileColor; if (myImage != null) { BitmapImage bi = new BitmapImage(); bi.CreateOptions = BitmapCreateOptions.BackgroundCreation; ImageBrush imageBrush = new ImageBrush(); using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication()) { if (myIsolatedStorage.FileExists(myImage)) { using ( IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(myImage, FileMode.Open, FileAccess.Read)) { bi.SetSource(fileStream); imageBrush.ImageSource = bi; } } else { return result; } } return imageBrush; } else { return result; } } 

我需要以某种方式更新/刷新网格标签或值转换器,以便它可以显示最新的更改!

编辑

添加了更多代码

该模型 :

  [Table] public class People : INotifyPropertyChanged, INotifyPropertyChanging { private int _peopleId; [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)] public int PeopleId { get { return _peopleId; } set { if (_peopleId != value) { NotifyPropertyChanging("PeopleId"); _peopleId = value; NotifyPropertyChanged("PeopleId"); } } } private string _peopleName; [Column] public string PeopleName { get { return _peopleName; } set { if (_peopleName != value) { NotifyPropertyChanging("PeopleName"); _peopleName = value; NotifyPropertyChanged("PeopleName"); } } } private string _tileColor; [Column] public string TileColor { get { return _tileColor; } set { if (_tileColor != value) { NotifyPropertyChanging("TileColor"); _tileColor = value; NotifyPropertyChanged("TileColor"); } } } private string _image; [Column] public string Image { get { return _image; } set { if (_image != value) { NotifyPropertyChanging("Image"); _image = value; NotifyPropertyChanged("Image"); } } } [Column] internal int _groupId; private EntityRef _group; [Association(Storage = "_group", ThisKey = "_groupId", OtherKey = "Id", IsForeignKey = true)] public Groups Group { get { return _group.Entity; } set { NotifyPropertyChanging("Group"); _group.Entity = value; if (value != null) { _groupId = value.Id; } NotifyPropertyChanging("Group"); } } [Column(IsVersion = true)] private Binary _version; #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion #region INotifyPropertyChanging Members public event PropertyChangingEventHandler PropertyChanging; private void NotifyPropertyChanging(string propertyName) { if (PropertyChanging != null) { PropertyChanging(this, new PropertyChangingEventArgs(propertyName)); } } #endregion } 

ViewModel:

 public class PeopleViewModel : INotifyPropertyChanged { private PeopleDataContext PeopleDB; // Class constructor, create the data context object. public PeopleViewModel(string PeopleDBConnectionString) { PeopleDB = new PeopleDataContext(PeopleDBConnectionString); } private ObservableCollection _allPeople; public ObservableCollection AllPeople { get { return _allPeople; } set { _allPeople = value; NotifyPropertyChanged("AllPeople"); } } public ObservableCollection LoadPeople(int gid) { var PeopleInDB = from People in PeopleDB.People where People._groupId == gid select People; AllPeople = new ObservableCollection(PeopleInDB); return AllPeople; } public void updatePeople(int cid, string cname, string image, string tilecol) { People getc = PeopleDB.People.Single(c => c.PeopleId == cid); getc.PeopleName = cname; getc.Image = image; getc.TileColor = tilecol; PeopleDB.SubmitChanges(); } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion } 

申请页面

                  

应用页面代码背后

 public partial class PeopleList : PhoneApplicationPage { private int gid; private bool firstRun; public PeopleList() { InitializeComponent(); firstRun = true; this.DataContext = App.ViewModel; } protected override void OnNavigatedTo(NavigationEventArgs e) { gid = int.Parse(NavigationContext.QueryString["Id"]); if (firstRun) { App.ViewModel.LoadPeople(gid); firstRun = false; } } } 

Background="{Binding Converter={StaticResource ImageConverter}}"建议您直接绑定到People (这是刷新时的问题)。

所以,你应该重新安排一下。 将其设为其他“更高”数据上下文a property


如何重新安排事情:

1) 你的’模型’(来自db的实体)应该与你的视图模型不同 。 为了避免进入细节,它解决了很多问题 – 例如你所拥有的。 People getters / setter通常不会以这种方式覆盖(EF经常使用reflection来处理w /实体等)。
因此,使PeopleVM(对于单人或PersonViewModel ) – 在那里复制东西 – 并在那里制作INotify – 留下人们只是一个纯粹的实体/ poco w /自动获取/设置。

2) PeopleViewModel也是PeopleViewModel – 它与Db过于紧密(这些也是设计指南)。
你不应该重用DbContext – 不要保存它 – 它是一个’一次性’对象(并缓存在里面) – 所以使用using()来按需处理和加载/更新。

3) 用PersonViewModel替换主VM中的People 。 当您从db加载时,首先将其泵入PersonVM – 当您以相反的方式保存时。 对于MVVM来说这是一个棘手的问题,你经常需要复制/复制 – 你可以使用一些工具来自动化或只是复制ctor-s或其他东西。
您的ObservableCollection AllPeople成为ObservableCollection AllPeople

4)XAML – 您的绑定AllPeople,PeopleName是相同的 – 但现在指向视图模型(和名称到VM名称)。
但是你应该将你的grid绑定到PersonViewModel (旧人)以外的东西 – 因为在集合内部很难“刷新”。
a)创建一个新的单一属性,如ImageAndTileColor – 并确保它在/当两个属性中的任何一个更改时更新/通知。
b)另一种选择是使用MultiBinding – 并绑定2,3个属性 – 一个是你拥有的整个PersonViewModel ,再加上其他两个属性 – 例如..

             

这样你就可以在3次更改中强制绑定刷新 – 你仍然拥有完整的People(实际上你可以只使用两个,因为你需要的只有Image和TileColor)。

5)将您的转换器更改为IMultiValue …并读取发送的多个值。

就这样 :)

精简版:
这是proper way并确定工作(这取决于你如何/何时更新Person属性等) – 但你可以先尝试short version – 只需在People模型上做multi-binding部分 – 并希望它能够工作。 如果不是,你必须做以上所有。

Windows Phone 7:
由于没有MultiBinding ……
– 使用变通方法 – 它应该非常相似,
– 或者使用(a)上面的绑定网格到{Binding ImageAndTileColor, Converter...} 。 创建新属性(如果您希望在实体/模型中执行相同操作 – 只需将其标记为[NotMapped()] ),这将是一个“复合” [NotMapped()]


http://www.thejoyofcode.com/MultiBinding_for_Silverlight_3.aspx

我明白了(感谢NSGaga)。 我把他的post作为答案,以下是我所做的

首先,我需要使转换器接收PeopleId而不是对象本身

 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int cid = (int)value; People myC = App.ViewModel.getPerson(cid); string myImage = myC.Image; object result = myC.TileColor; if (myImage != null) { BitmapImage bi = new BitmapImage(); bi.CreateOptions = BitmapCreateOptions.BackgroundCreation; ImageBrush imageBrush = new ImageBrush(); using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication()) { if (myIsolatedStorage.FileExists(myImage)) { using ( IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(myImage, FileMode.Open, FileAccess.Read)) { bi.SetSource(fileStream); imageBrush.ImageSource = bi; } } else { return result; } } return imageBrush; } else { return result; } } 

然后我只需要添加调用NotifyPropertyChanged("PeopleId")每当我像这样更新Image或TileColor

  private string _tileColor; [Column] public string TileColor { get { return _tileColor; } set { if (_tileColor != value) { NotifyPropertyChanging("TileColor"); _tileColor = value; NotifyPropertyChanged("TileColor"); NotifyPropertyChanged("PeopleId"); } } } private string _image; [Column] public string Image { get { return _image; } set { if (_image != value) { NotifyPropertyChanging("Image"); _image = value; NotifyPropertyChanged("Image"); NotifyPropertyChanged("PeopleId"); } } } 

这会强制值转换器刷新:)