0

Fellow WPF coders, I am not unable to bind the source of an image using a BitMapImage property( ImageSource) in the ViewModel. I implemented INotifyPropertyChanged on this property, I looked up several pages on this website and tried the solutions, The snoop tool shows that the property binding was correct with the path to the image file in resources. But I can't see the image on each list view item when I select it. Please take a look at the BindImages Function and the xaml for the image . I also tried moving the property to the the actual object in the myList collection. But I still don't see the image at run time. Here is the code:

    <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
0

3 Answers 3

0

Your TestViewModel class doesn't implement INotifyPropertyChanged interfrace. Add :INotifyPropertyChanged after public class TestViewModel.

Sign up to request clarification or add additional context in comments.

1 Comment

My TestViewModel does implement INotifyPropertychanged, but I did not copy the code here.
0

Looking at your Converter code where you are expecting a string value, your ImageSource property should be string type. And Even if you have taken ImageSource property as BitmapImage, you are not setting it, you are setting, _imagesource variable which won't send any notification to the view. For notification, you should set, ImageSource property instead of _imagesource variable. Also if you are taking ImageSource property as BitmapImage, you don't need Converter, you can directly bind this property with the Source property of Image.

2 Comments

I totally agree. I made the requested changes and also updated the question.(I removed the imageconverter from the binding, I tested it, It still does not show the image .
Put a break point in BindImages` method and check, if method is being called or not. Because that is the only method where you are setting Imagesource property.
0

I got this resolved finally. All I had to do was to create an ImageString string property in my Test object not in the ViewModel. I set this to string .empty, but when the binding happens, I assigned the URI path to it.

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}"/> 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.