在视图模型中使用BitMapImage属性的图像绑定不起作用
本文关键字:属性 图像 绑定 不起作用 BitMapImage 视图 模型 | 更新日期: 2023-09-27 17:49:30
WPF程序员,我不是不能在ViewModel中使用BitMapImage属性(ImageSource)绑定图像的源。我在这个属性上实现了INotifyPropertyChanged,我在这个网站上查找了几个页面并尝试了解决方案,snoop工具显示属性绑定与资源中图像文件的路径是正确的。但是,当我选择每个列表视图项时,我无法看到它的图像。请查看BindImages函数和图像的xaml。我还尝试将属性移动到myList集合中的实际对象。但在运行时我仍然看不到图像。下面是代码:
<Window x:Class="TestProject.View.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:me="clr-namespace:TestProject.Model"
xmlns:local="clr-namespace:TestProject.Framework.Converter"
xmlns:view="clr-namespace:TestProject.View"
xmlns:viewmodel="clr-namespace:TestProject.ViewModel"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
DataContext="{Binding Test, Source={StaticResource Locator}}"
Title="Test Overview" Height="300" Width="500" Icon="/TestProject;component/Resources/TestProject.png" Background="{StaticResource {x:Static SystemColors.ControlBrushKey}}" WindowStartupLocation="CenterScreen">
<Window.Resources>
<local:ImageConverter x:Key="imageConverter"/>
</Window.Resources>
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="220" />
</Grid.ColumnDefinitions>
<Menu Grid.ColumnSpan="3">
<MenuItem Header="File">
<MenuItem Header="Close" />
</MenuItem>
<MenuItem Header="Edit">
<MenuItem Header="Select" Command ="{Binding SelectCmd}" IsEnabled="{Binding Path=SelectedIndex, ElementName=listView, Converter={StaticResource ResourceKey=enableConverter}}"
ToolTip="Selects the test so the results are displayed in the main window for quick reference." >
<MenuItem.Icon>
<Image Source="/TestProject;component/Resources/Testimage.gif" Height="16" Width="16" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
<ListView Name="listView" ItemsSource="{Binding Source={myList}}" SelectedItem="{Binding SelectedTest, Mode=TwoWay}" SelectionMode="Single" Grid.RowSpan="2" Grid.Row="1" >
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Select" Name="menuSelect" Command ="{Binding SelectCmd}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},
Path=PlacementTarget.DataContext}"
ToolTip="Selects the test so the results are displayed in the main window for quick reference.">
<MenuItem.Icon>
<Image Source="/TestProject;component/Resources/Testimage.gif" Height="16" Width="16" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListView.ContextMenu>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Width="12" Height="12" Source="{Binding ImageSource}" DataContext="{Binding Test, Source={StaticResource Locator}}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
ImageConverter.cs
public sealed class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
try
{
return new BitmapImage(new Uri((string)value));
}
catch
{
return new BitmapImage();
}
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
TestViewmodel.cs
public class TestViewModel
{
#region Fields
private BitmapImage _imagesource;
#endregion
#region Properties
public BitmapImage ImageSource
{
get
{
return _imagesource;
}
set
{
_imagesource = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("ImageSource");
}
}
#endregion
#region Relay Commands
/// <summary>
/// Command that selects the test in the list of the tests.
/// </summary>
public RelayCommand SelectCmd { get; private set; }
/// <summary>
/// Command to select the tested subdivision from the context menu of the list view
/// </summary>
public RelayCommand<MenuClass> ContextSelectCmd { get; private set; }
#endregion
public TestViewModel()
{
_imagesource = new BitmapImage();
TestProject.Instance.PropertyChanged += TestProject_SelectedChange_Changed;
ContextSelectCmd = new RelayCommand<MenuClass>(SelectMenuItem);
SelectCmd = new RelayCommand(() => SelectTest(), () => true);
}
private void TestProject_SelectedChange_Changed(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
try
{
if (e.PropertyName == "SelectedTest")
{
//Select the selected item.
Dispatcher.CurrentDispatcher.DynamicInvoke(BindImages);
}
}
catch (Exception ex)
{
ErrorLogger.Log(LogLevel.Error, ex.ToString());
}
}
/// <summary>
/// Sets the selection checkmarks.
/// </summary>
public void BindImages()
{
List<Test> myTests= new List<Test>();
foreach (var item in TestProject.Instance.TestHistory.Values)
{
myTests = item;
foreach (Test test in myTests)
{
if (TestProject.Instance.SelectedTest.ContainsKey(test.Order.Id))
{
if (TestProject.Instance.SelectedTest[test.Order.Id] == test)
{
Dispatcher.CurrentDispatcher.DynamicInvoke(delegate()
{
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri(@"/TestProject;component/Resources/Testimage.gif", UriKind.Relative);
logo.EndInit();
Imagesource = logo;
});
}
}
}
}
}
private void SelectMenuItem ( MenuClass m )
{
try
{
Test t = SelectedTest as Test;
if (t != null)
{
Test tst = t;
if (TestProject.Instance.SelectedTest.ContainsKey(tst.Order.Id))
{
TestProject.Instance.SelectedTest[tst.Order.Id] = tst;
}
else
{
TestProject.Instance.SelectedTest.Add(tst.Order.Id, tst);
}
TestProject.Instance.OnPropertyChanged("SelectedTest");
}
}
catch (Exception ex)
{
ErrorLogger.Log(LogLevel.Error, ex.ToString());
}
}
#region INotifyPropertyChanged Members
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Safely raises the PropertyChanged event.
/// </summary>
/// <param name="property">The property name.</param>
protected void OnPropertyChanged(string Status)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(Status));
}
}
#endregion
你的TestViewModel类没有实现INotifyPropertyChanged接口。在公共类TestViewModel之后添加:INotifyPropertyChanged .
查看您期望string
值的Converter
代码,您的ImageSource
属性应该是string
类型。即使你将ImageSource
属性设置为BitmapImage
,你也没有设置它,你设置的是_ imagesource
变量它不会向视图发送任何通知。对于通知,您应该设置,ImageSource
属性而不是_ imagesource
变量。另外,如果您将ImageSource
属性作为BitmapImage
,则不需要Converter
,您可以直接将该属性与Image
的Source
属性绑定。
我终于解决了这个问题。我所要做的就是在我的测试对象中创建一个ImageString字符串属性,而不是在ViewModel中。我将它设置为string .empty,但是当绑定发生时,我为它分配了URI路径。
Test.cs
/// <summary>
/// Represents a test validation result.
/// </summary>
internal class Test : INotifyPropertyChanged
{
private string _imgstring = string.Empty;
public string ImageString
{
get
{
return _imgstring;
}
set
{
_imgstring = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("ImageString");
}
}
}
TestViewModel.cs
/// <summary>
/// Sets the selection checkmarks.
/// </summary>
public void BindImages()
{
List<Test> myTests= new List<Test>();
foreach (var item in TestProject.Instance.TestHistory.Values)
{
myTests = item;
foreach (Test test in myTests)
{
if (TestProject.Instance.SelectedTest.ContainsKey(test.Order.Id))
{
if (TestProject.Instance.SelectedTest[test.Order.Id] == test)
{
Dispatcher.CurrentDispatcher.DynamicInvoke(delegate()
{
test.ImageString=@"/TestProject;component/Resources/Testimage.gif"
});
}
}
}
}
}
xaml: <Image Width="12" Height="12" Source="{Binding ImageString}"/>