将图像绑定到wpf中的嵌入式资源
Binding image to embedded resource in wpf
我是 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.
当您绑定到 CurrentImage 并且 CurrentImage 的值发生变化时,您必须引发 属性 changed 事件当前图片.
根据提供的代码,您也可以这样做:
public Uri currentImageNotifier
{
get { return CurrentImage; }
set
{
CurrentImage = value;
RaisePropertyChanged("CurrentImage");
}
}
当您绑定到一个可观察的集合时,您正在订阅集合中的更改(例如,从集合中添加或删除项目)。这不会让您订阅集合中各个项目的属性更改。正如其他人所说,如果您想绑定到项目上的 属性,则需要在 属性 更改时引发 PropertyChanged
事件。
private Uri currentImage;
public Uri CurrentImage
{
get { return currentImage; }
set
{
currentImage = value;
RaisePropertyChanged("CurrentImage");
}
}
注意:您可能希望将 setter 包装在 if
语句中并使用 Uri.Compare()
来确定给定值是否为实际上与当前值不同。这样,您只会在 属性 实际更改时引发 PropertyChanged
事件。
此外,在您的代码示例中,您在此 foreach
循环中设置 CurrentImage
属性:
foreach(var comp in CompListObs)
{
comp.CurrentImage = ResourceHelper.LoadBitmapURIFromResource("another image");
}
但是,您从 currentImageNotifier
属性 引发了 PropertyChanged
事件。可以从正在修改的 属性 之外的位置引发 PropertyChanged
事件,但是您需要将 foreach
循环中的 CurrentImage
赋值替换为 currentImageNotifier
,或修改您的 CurrentImage
属性 以引发其自己的 PropertyChanged
事件。就目前而言,您实际上并没有在要绑定的 属性 上引发 PropertyChanged
事件。
老实说,您似乎甚至不需要 currentImageNotifier
属性。它没有做任何你不能直接用 CurrentImage
属性 做的事情。
我是 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.
当您绑定到 CurrentImage 并且 CurrentImage 的值发生变化时,您必须引发 属性 changed 事件当前图片.
根据提供的代码,您也可以这样做:
public Uri currentImageNotifier
{
get { return CurrentImage; }
set
{
CurrentImage = value;
RaisePropertyChanged("CurrentImage");
}
}
当您绑定到一个可观察的集合时,您正在订阅集合中的更改(例如,从集合中添加或删除项目)。这不会让您订阅集合中各个项目的属性更改。正如其他人所说,如果您想绑定到项目上的 属性,则需要在 属性 更改时引发 PropertyChanged
事件。
private Uri currentImage;
public Uri CurrentImage
{
get { return currentImage; }
set
{
currentImage = value;
RaisePropertyChanged("CurrentImage");
}
}
注意:您可能希望将 setter 包装在 if
语句中并使用 Uri.Compare()
来确定给定值是否为实际上与当前值不同。这样,您只会在 属性 实际更改时引发 PropertyChanged
事件。
此外,在您的代码示例中,您在此 foreach
循环中设置 CurrentImage
属性:
foreach(var comp in CompListObs)
{
comp.CurrentImage = ResourceHelper.LoadBitmapURIFromResource("another image");
}
但是,您从 currentImageNotifier
属性 引发了 PropertyChanged
事件。可以从正在修改的 属性 之外的位置引发 PropertyChanged
事件,但是您需要将 foreach
循环中的 CurrentImage
赋值替换为 currentImageNotifier
,或修改您的 CurrentImage
属性 以引发其自己的 PropertyChanged
事件。就目前而言,您实际上并没有在要绑定的 属性 上引发 PropertyChanged
事件。
老实说,您似乎甚至不需要 currentImageNotifier
属性。它没有做任何你不能直接用 CurrentImage
属性 做的事情。