![](/img/trans.png)
[英]INotifyPropertyChanged is not refreshing my listview in WPF MVVM entity
[英]refreshing Value Converter on INotifyPropertyChanged
我知道這里有一些類似的主題,但我無法得到任何答案。 我必須在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
某些其他“更高”數據上下文a property
。
如何重新安排事情:
1) 您的“模型”(來自db的實體)應該與您的視圖模型不同 。 為了避免詳細說明,它解決了許多問題 - 例如你所擁有的問題。 People
getters / setter通常不以這種方式覆蓋(EF經常使用反射來處理w /實體等)。
因此,讓PeopleVM(對於單人或PersonViewModel
) - 在那里復制東西 - 並在那里制作INotify - 留下人們只是一個純粹的實體/ poco w /自動獲取/設置。
2) PeopleViewModel
也是PeopleViewModel
- 它與Db過於緊密(這些也是設計指南)。
你不應該重用DbContext - 不要保存它 - 它是一個'一次性'對象(並緩存在里面) - 所以使用using()
來按需處理和加載/更新。
3) 用PersonViewModel替換主VM中的People 。 當您從db加載時,首先將其泵入PersonVM - 當您以相反的方式保存時。 對於MVVM來說這是一個棘手的問題,你經常需要復制/復制 - 你可以使用一些工具來自動化或只是復制ctor-s或其他東西。
你的ObservableCollection<People> AllPeople
成為ObservableCollection<PersonViewModel> AllPeople
4)XAML - 您的綁定AllPeople,PeopleName是相同的 - 但現在指向視圖模型(和名稱到VM名稱)。
但是你應該將你的grid
綁定到PersonViewModel
(舊人)以外的東西 - 因為在集合內部很難“刷新”。
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)將您的轉換器更改為IMultiValue ...並讀取發送的多個值。
就這樣 :)
簡潔版本:
這是proper way
並確定工作(這取決於你如何/何時更新Person屬性等) - 但你可以先嘗試short version
- 只需在People模型上做multi-binding
部分 - 並希望它能夠工作。 如果不是,你必須做以上所有。
Windows Phone 7:
由於沒有MultiBinding
......
- 使用變通方法 - 它應該非常相似,
- 或者使用上面的(a)
- 綁定網格到{Binding ImageAndTileColor, Converter...}
。 創建新屬性(如果您希望在實體/模型中也可以這樣做 - 只需將其標記為[NotMapped()]
),這將是一個“復合” [NotMapped()]
。
我明白了(感謝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;
}
}
然后,每當我像這樣更新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");
}
}
}
這會強制值轉換器刷新:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.