[英]refreshing Value Converter on INotifyPropertyChanged
I know there are some similar topics here but I couldn't get any answer from them. 我知道这里有一些类似的主题,但我无法得到任何答案。 I have to update background of a grid to either an image or a colour in my Windows Phone 7 app. 我必须在Windows Phone 7应用程序中将网格背景更新为图像或颜色。 I do this using my value converter , it works fine but I'd have to reload the collection so it updates the colour or image. 我使用我的值转换器,它工作正常,但我必须重新加载集合,以便更新颜色或图像。
<Grid Background="{Binding Converter={StaticResource ImageConverter}}" Width="125" Height="125" Margin="6">
The converter receives the object then gets the color and image from it, here is the converter 转换器接收对象然后从中获取颜色和图像,这里是转换器
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;
}
}
I need to somehow update/refresh the grid tag or the value converter so that it can show the latest changes ! 我需要以某种方式更新/刷新网格标签或值转换器,以便它可以显示最新的更改!
EDIT 编辑
ADDED SOME MORE CODE 添加了更多代码
The model : 该模型 :
[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<Groups> _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 : 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<People> _allPeople;
public ObservableCollection<People> AllPeople
{
get { return _allPeople; }
set
{
_allPeople = value;
NotifyPropertyChanged("AllPeople");
}
}
public ObservableCollection<People> LoadPeople(int gid)
{
var PeopleInDB = from People in PeopleDB.People
where People._groupId == gid
select People;
AllPeople = new ObservableCollection<People>(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
}
Application Page 申请页面
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Margin="0,8,0,0" x:Name="Peoplelist" HorizontalAlignment="Center" BorderThickness="4" ItemsSource="{Binding AllPeople}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="{Binding Converter={StaticResource ImageConverter}}" Width="125" Height="125" Margin="6">
<TextBlock Name="name" Text="{Binding PeopleName}" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
Application Page code behind 应用程序页面代码
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}}"
suggests you bind directly to People
item (which is your problem when refreshing). Background="{Binding Converter={StaticResource ImageConverter}}"
建议您直接绑定到People
项 (这是刷新时的问题)。
So, you should rearrange a bit. 所以,你应该重新安排一下。 Make that a property
of some other 'higher' data context instead. 将其a property
某些其他“更高”数据上下文a property
。
How to rearrange things: 如何重新安排事情:
1) your 'model' (entity from db) should be different than your view-model . 1) 您的“模型”(来自db的实体)应该与您的视图模型不同 。 To avoid going into details, it solves lot of problems - eg like you're having. 为了避免详细说明,它解决了许多问题 - 例如你所拥有的问题。 The People
getters/setters are not normally overriden in that way (EF often uses reflection to deal w/ entities etc.). People
getters / setter通常不以这种方式覆盖(EF经常使用反射来处理w /实体等)。
So, make PeopleVM (for single People or PersonViewModel
) - copy things in there - and make INotify in there - leave People just a pure entity/poco w/ automatic get/set. 因此,让PeopleVM(对于单人或PersonViewModel
) - 在那里复制东西 - 并在那里制作INotify - 留下人们只是一个纯粹的实体/ poco w /自动获取/设置。
2) Same for the PeopleViewModel
- it's too tied-up to the Db (these are also design guidelines). 2) PeopleViewModel
也是PeopleViewModel
- 它与Db过于紧密(这些也是设计指南)。
You shouldn't reuse the DbContext - don't save it - it's a 'one off' object (and cached inside) - so use using()
to deal with and load/update on demand. 你不应该重用DbContext - 不要保存它 - 它是一个'一次性'对象(并缓存在里面) - 所以使用using()
来按需处理和加载/更新。
3) Replace People in your main VM with PersonViewModel . 3) 用PersonViewModel替换主VM中的People 。 When you load from db, pump up into the PersonVM first - when you're saving the other way around. 当您从db加载时,首先将其泵入PersonVM - 当您以相反的方式保存时。 That's a tricky bit with MVVM, you often need to copy/duplicate - you could use some tool for that to automate or just make copy ctor-s or something. 对于MVVM来说这是一个棘手的问题,你经常需要复制/复制 - 你可以使用一些工具来自动化或只是复制ctor-s或其他东西。
Your ObservableCollection<People> AllPeople
becomes ObservableCollection<PersonViewModel> AllPeople
你的ObservableCollection<People> AllPeople
成为ObservableCollection<PersonViewModel> AllPeople
4) XAML - your binding AllPeople, PeopleName is the same - but that points now to view-models (and Name to VM Name). 4)XAML - 您的绑定AllPeople,PeopleName是相同的 - 但现在指向视图模型(和名称到VM名称)。
But you should bind your grid
to something other than PersonViewModel
(old People) - as that is hard to 'refresh' when inside the collection. 但是你应该将你的grid
绑定到PersonViewModel
(旧人)以外的东西 - 因为在集合内部很难“刷新”。
a) Make a new single property like ImageAndTileColor
- and make sure it updates/notifies on / when any of the two properties change. a)创建一个新的单一属性,如ImageAndTileColor
- 并确保它在/当两个属性中的任何一个更改时更新/通知。
b) The other option is to use MultiBinding
- and bind 2, 3 properties - one being the whole PersonViewModel
like you have and plus those other two properties - eg.. b)另一个选择是使用MultiBinding
- 并绑定2,3个属性 - 一个是你拥有的整个PersonViewModel
,再加上其他两个属性 - 例如..
<Grid ...>
<Grid.Background>
<MultiBinding Converter="{StaticResource ImageConverter}" Mode="OneWay">
<MultiBinding.Bindings>
<Binding Path="Image" />
<Binding Path="TileColor" />
<Binding Path="" />
</MultiBinding.Bindings>
</MultiBinding>
</Grid.Background>
<TextBlock Name="name" Text="{Binding PeopleName}" ... />
</Grid>
That way you force the binding to refresh when any of the 3 changes - and you still have your full People in there (actually you could just use two as all you need is Image and TileColor). 这样你就可以在3次更改时强制绑定刷新 - 你仍然拥有完整的People(实际上你可以只使用两个,因为你需要的只有Image和TileColor)。
5) Change your Converter to be IMultiValue... and to read multiple values sent in. 5)将您的转换器更改为IMultiValue ...并读取发送的多个值。
That's all :) 就这样 :)
SHORT VERSION: 简洁版本:
That was the proper way
and certain to work (it depends on how/when you update Person properties etc.) - but you could try the short version
first - just do the multi-binding
part on the People model - and hope it'd work. 这是proper way
并确定工作(这取决于你如何/何时更新Person属性等) - 但你可以先尝试short version
- 只需在People模型上做multi-binding
部分 - 并希望它能够工作。 If it doesn't you have to do all the above. 如果不是,你必须做以上所有。
Windows Phone 7: Windows Phone 7:
Since there is no MultiBinding
... 由于没有MultiBinding
......
- Use the workaround - it should be quite similar, - 使用变通方法 - 它应该非常相似,
- Or go with the (a)
above - bind grid to {Binding ImageAndTileColor, Converter...}
. - 或者使用上面的(a)
- 绑定网格到{Binding ImageAndTileColor, Converter...}
。 Make new property (you can do the same if you wish in the entity/model - just mark it as [NotMapped()]
) which would be a 'composite' one. 创建新属性(如果您希望在实体/模型中也可以这样做 - 只需将其标记为[NotMapped()]
),这将是一个“复合” [NotMapped()]
。
I got it (Thanks to NSGaga). 我明白了(感谢NSGaga)。 I set his post as the answer, the following is what I did 我把他的帖子作为答案,以下是我所做的
First I needed to make the converter to receive PeopleId instead of the object itself 首先,我需要使转换器接收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;
}
}
Then I just had to add call NotifyPropertyChanged("PeopleId")
whenever I update Image or TileColor like this 然后,每当我像这样更新Image或TileColor时,我只需要添加调用NotifyPropertyChanged("PeopleId")
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");
}
}
}
This forces the value converter to refresh :) 这会强制值转换器刷新:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.