在视图模型中使用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

在视图模型中使用BitMapImage属性的图像绑定不起作用

你的TestViewModel类没有实现INotifyPropertyChanged接口。在公共类TestViewModel之后添加:INotifyPropertyChanged .

查看您期望string值的Converter代码,您的ImageSource属性应该是string类型。即使你将ImageSource属性设置为BitmapImage,你也没有设置它,你设置的是_ imagesource变量它不会向视图发送任何通知。对于通知,您应该设置,ImageSource属性而不是_ imagesource变量。另外,如果您将ImageSource属性作为BitmapImage,则不需要Converter,您可以直接将该属性与ImageSource属性绑定。

我终于解决了这个问题。我所要做的就是在我的测试对象中创建一个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}"/>