我是WPF的新手,我遇到了问题。我有一个ListBox,图像排列在一个平面图中,图像源绑定到代码中的uri。 uri是项目中的嵌入式资源。这一切在启动时都能正常工作,直到我必须更改图像。没有例外,但图像不会改变。当我在调试中运行时,我可以看到即使ObservableCollection项目发生更改,主窗口图像也不会。
这是由于缓存,还是其他原因?我尝试在xaml中禁用缓存,但是我收到错误The TypeConverter for "CacheMode" does not support converting from a string.
我会尽力简要介绍代码,并且只包含相关信息:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public ObservableCollection<ComputerInfo> CompListObs;
public ObservableCollection<ComputerInfo> compListObsNotifier
{
get { return CompListObs; }
set
{
CompListObs = value;
RaisePropertyChanged("compListObsNotifier");
}
}
//...
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
// This correctly loads the images from the xml and displays them on the main window:
var items = XDocument.Load(@"path to xml")
.Descendants("Computer")
.Select(i => new ComputerInfo {
MachineName = (string)i.Element("MachineName"),
Lat = (double)i.Element("Long"),
Lon = (double)i.Element("Lat"),
CurrentImage = ResourceHelper.LoadBitmapURIFromResource((string)i.Element("Img"))
}).ToList();
CompListObs = new ObservableCollection<ComputerInfo>(items);
}
public void MainTimer_Tick(object sender, EventArgs e)
{
// This runs fine and I can see the members of CompListObs are changing,
// but the images on the mainwindow are not changing.
foreach(var comp in CompListObs) { comp.CurrentImage = ResourceHelper.LoadBitmapURIFromResource("another image");
}
// INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public class ComputerInfo : INotifyPropertyChanged
{
public ClientInfo ClientsInfo { get; set; }
public string MachineName { get; set; }
public Uri CurrentImage { set; get; }
public double Lat { get; set; }
public double Lon { get; set; }
public Uri currentImageNotifier
{
get { return CurrentImage; }
set
{
CurrentImage = value;
RaisePropertyChanged("compListObsNotifier");
}
}
// INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void RaisePropertyChanged(string propName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
这是xaml:
<ListBox ItemsSource="{Binding compListObsNotifier}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=CurrentImage}" Height="65"></Image>
</DataTemplate>
</ListBox.ItemTemplate>
<!-- after this, I place <ListBox.ItemsPanel> <ItemsPanelTemplate> and <Canvas> in the ListBox.
答案 0 :(得分:1)
当您绑定到 CurrentImage 并且 CurrentImage 的值发生更改时,您必须为 CurrentImage 引发属性更改事件。
根据提供的代码,您也可以这样做:
public Uri currentImageNotifier
{
get { return CurrentImage; }
set
{
CurrentImage = value;
RaisePropertyChanged("CurrentImage");
}
}
答案 1 :(得分:1)
绑定到可观察集合时,您正在订阅集合中的更改(例如,在集合中添加或删除项目)。这不会订阅您对集合中各个项目的属性的更改。正如其他人所说,如果要绑定到项目上的属性,则需要在属性更改时引发PropertyChanged
事件。
private Uri currentImage;
public Uri CurrentImage
{
get { return currentImage; }
set
{
currentImage = value;
RaisePropertyChanged("CurrentImage");
}
}
注意:您可能希望将setter包装在if
语句中并使用Uri.Compare()
来确定给定值是否实际上与当前值不同。这样,您只会在属性实际更改时引发PropertyChanged
事件。
此外,在您的代码示例中,您要在此CurrentImage
循环中设置foreach
属性:
foreach(var comp in CompListObs)
{
comp.CurrentImage = ResourceHelper.LoadBitmapURIFromResource("another image");
}
但是,您要从PropertyChanged
属性中提升currentImageNotifier
事件。可以从正在修改的媒体资源之外的位置提升PropertyChanged
个事件,但您需要使用{{1}替换CurrentImage
循环中的foreach
作业},或修改您的currentImageNotifier
属性以提升自己的CurrentImage
事件。就目前情况而言,您实际上并未在您绑定的属性上举起PropertyChanged
事件。
老实说,看起来你甚至不需要PropertyChanged
属性。它没有做任何你不能直接使用currentImageNotifier
财产的事情。