【问题标题】:Image binding using a BitMapImage property in the viewmodel does not work在视图模型中使用 BitMapImage 属性的图像绑定不起作用
【发布时间】:2015-07-30 01:25:10
【问题描述】:

各位 WPF 编码人员,我无法使用 ViewModel 中的 BitMapImage 属性 (ImageSource) 绑定图像的源。我在这个属性上实现了 INotifyPropertyChanged,我在这个网站上查找了几个页面并尝试了解决方案,窥探工具显示属性绑定与资源中图像文件的路径是正确的。但是当我选择它时,我看不到每个列表视图项上的图像。请查看图像的 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

【问题讨论】:

    标签: c# wpf mvvm-light


    【解决方案1】:

    我终于解决了这个问题。我所要做的就是在我的测试对象中而不是在 ViewModel 中创建一个 ImageString 字符串属性。我将它设置为字符串 .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}"/> 
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 我完全同意。我进行了请求的更改并更新了问题。(我从绑定中删除了 imageconverter,我对其进行了测试,它仍然没有显示图像。
      • 在 BindImages 方法中放置一个断点并检查是否正在调用该方法。因为这是您设置 Imagesource 属性的唯一方法。
      【解决方案3】:

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

      【讨论】:

      • 我的TestViewModel确实实现了INotifyPropertychanged,但是这里没有复制代码。
      猜你喜欢
      • 2016-06-14
      • 2010-12-02
      • 1970-01-01
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-26
      • 2014-06-18
      • 1970-01-01
      相关资源
      最近更新 更多