刷新INotifyPropertyChanged上的值转换器
本文关键字:转换器 INotifyPropertyChanged 刷新 | 更新日期: 2023-09-27 18:07:51
我知道这里有一些类似的话题,但我无法从他们那里得到任何答案。我必须在我的Windows Phone 7应用程序中将网格的背景更新为图像或颜色。我使用我的值转换器来完成此操作,它工作得很好,但我必须重新加载集合,以便更新颜色或图像。
<Grid Background="{Binding Converter={StaticResource ImageConverter}}" Width="125" Height="125" Margin="6">
转换器接收对象,然后从中获取颜色和图像,这是转换器
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<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:
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
}
应用程序页面
<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>
应用程序页面代码
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) 你的'模型'(实体从数据库)应该不同于你的视图模型。为了避免深入细节,它解决了很多问题——比如你现在。People
getter/setter通常不会以这种方式被重写(EF经常使用反射来处理/实体等)。
因此,创建PeopleVM(用于单个People或PersonViewModel
) -在那里复制东西-并在那里创建INotify -让People只是一个纯实体/poco/自动获取/设置。
2)同样的PeopleViewModel
-它太绑定到Db(这些也是设计指南)。
你不应该重用DbContext -不要保存它-它是一个'一次性'对象(和缓存在里面)-所以使用using()
来处理和加载/更新的需求。
3) 用PersonViewModel替换主VM中的People。当您从db加载时,首先将泵入PersonVM -当您以相反的方式保存时。这是MVVM的一个棘手的地方,你经常需要复制/复制-你可以使用一些工具来自动化,或者只是制作复制因子或其他东西。
你的ObservableCollection<People> AllPeople
变成了ObservableCollection<PersonViewModel> AllPeople
4) XAML -您的绑定AllPeople, PeopleName是相同的-但现在指向视图模型(和名称到VM名称)。
但是你应该将你的grid
绑定到PersonViewModel
(old People)以外的东西 -因为在集合内很难"刷新"。
a)创建一个新的单一属性,如ImageAndTileColor
-并确保它更新/通知时,任何两个属性的变化。
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>
这样,当3个更改中的任何一个时,您强制绑定刷新-并且您仍然在那里拥有完整的People(实际上您可以只使用两个,因为您所需要的只是Image和TileColor)。
5)改变你的转换器是multivalue…并读取发送进来的多个值。
就这些了:)
短版:
这是proper way
,肯定能工作(这取决于你如何/何时更新Person属性等)-但你可以先尝试short version
-只要在People模型上做multi-binding
部分-并希望它能工作。如果没有,你就必须做以上所有的事情。
Windows Phone 7:
因为没有MultiBinding
…
-使用变通方法-它应该非常相似,
-或者将(a)
绑定到{Binding ImageAndTileColor, Converter...}
。创建新属性(如果您希望在实体/模型中也可以这样做-只需将其标记为[NotMapped()]
),这将是一个"复合"属性。
http://www.thejoyofcode.com/MultiBinding_for_Silverlight_3.aspx
我明白了(感谢NSGaga)。我把他的帖子作为答案,以下是我所做的
首先,我需要让转换器接收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;
}
}
然后我只需要添加call 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");
}
}
}
强制值转换器刷新:)