Home > OS >  Wpf binding image file to BitmapImage UriSource in MVVM way
Wpf binding image file to BitmapImage UriSource in MVVM way

Time:09-16

I'm desperatly triying to bound an image (which is located in a subdirectory of application installation directory). I'm Using MVVM and .Net 3.5, is'ts easy to find the image path and return either a String, an Uri or a Bitmap in a property and use it in the xaml.

I tryied all these three formats to bind to UriSource in Images.Resources, but none of them worked. I tried also to bound the UriSource with a String property with a Converter, no luck!

No image is displayed.

Is it possible to achieve that ? Then what am I missing ?

xaml:

<TreeView ItemsSource="{Binding ObCol_FamilyTree}">
   <i:Interaction.Behaviors>
      <behaviours:BindableTreeViewSelectedItemBehavior SelectedItem="{Binding TreeViewSelectedItem, Mode=TwoWay}" />
   </i:Interaction.Behaviors>
   <TreeView.Resources>
      <Style x:Key="ExpandingImageStyle" TargetType="{x:Type Image}">
         <Setter Property="Source" Value="{DynamicResource Icon_Closed}"/>
         <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=IsExpanded}" Value="True">
               <Setter Property="Source" Value="{DynamicResource Icon_Open}"/>
            </DataTrigger>
         </Style.Triggers>
      </Style> 
   </TreeView.Resources>
   <TreeView.ItemContainerStyle>
      <Style TargetType="{x:Type TreeViewItem}">
         <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
         <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
      </Style>
   </TreeView.ItemContainerStyle>

   <TreeView.ItemTemplate>
      <HierarchicalDataTemplate ItemsSource="{Binding ObCol_Items}">
         <StackPanel Orientation="Horizontal">
            <Image Width="16" Height="16" Margin="0,0,3,0" Style="{StaticResource ExpandingImageStyle}">
               <Image.Resources>
                  <BitmapImage x:Key="Icon_Closed" UriSource="{Binding OpenFolderPath, Converter={StaticResource UriConverter}}"/>
                  <BitmapImage x:Key="Icon_Open" UriSource="{Binding OpenFolderPath, Converter={StaticResource UriConverter}}" />
               </Image.Resources>
            </Image>
            <TextBlock Text="{Binding Name}" />
         </StackPanel>
      </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>

Viewmodel :

private string myOpenFolderPath;
public ItemListVM()
{
   myOpenFolderPath = AppDomain.CurrentDomain.BaseDirectory   @"..\images\Icon_Open.png";
   if (!File.Exists(myOpenFolderPath))
      myOpenFolderPath = String.Empty;
}

public string OpenFolderPath
{
   get { return Path.GetFullPath(myOpenFolderPath); }
}

Converter :

public class UriConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      return new Uri(value.ToString());
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      throw new NotSupportedException();
   }
 }

I tried the same with an Uri Property with a right Converter which is returning an Uri, no more luck!

EDIT : here is the solution:

<TreeView ItemsSource="{Binding ObCol_FamilyTree}">
   <i:Interaction.Behaviors>
      <behaviours:BindableTreeViewSelectedItemBehavior SelectedItem="{Binding TreeViewSelectedItem, Mode=TwoWay}" />
   </i:Interaction.Behaviors>
   <TreeView.Resources>
      <Style x:Key="ExpandingImageStyle" TargetType="{x:Type Image}">
         <Setter Property="Source" Value="{Binding DataContext.ClosedFolderPath, RelativeSource={RelativeSource AncestorType=TreeView}}"/>
         <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=IsExpanded}" Value="True">
               <Setter Property="Source" Value="{Binding DataContext.OpenFolderPath, RelativeSource={RelativeSource AncestorType=TreeView}}"/>
            </DataTrigger>
         </Style.Triggers>
      </Style> 
   </TreeView.Resources>
   <TreeView.ItemContainerStyle>
      <Style TargetType="{x:Type TreeViewItem}">
         <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
         <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
      </Style>
   </TreeView.ItemContainerStyle>

   <TreeView.ItemTemplate>
      <HierarchicalDataTemplate ItemsSource="{Binding ObCol_Items}">
         <StackPanel Orientation="Horizontal">
            <Image Width="16" Height="16" Margin="0,0,3,0" Style="{StaticResource ExpandingImageStyle}"/>
            <TextBlock Text="{Binding Name}" />
         </StackPanel>
      </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>

CodePudding user response:

Neither a BitmapImage resource nor a Binding Converter is needed.

This works out of the box, due to built-in type conversion from string to ImageSource:

<Setter Property="Source" Value="{Binding OpenedFolderPath}"/>

In the ItemTemplate of the TreeView this Binding will not work, because it doesn't have the expected DataContext. You would write

<Setter Property="Source" 
    Value="{Binding DataContext.OpenedFolderPath,
                    RelativeSource={RelativeSource AncestorType=TreeView}}"/>

Besides that, a converter for the UriSource property of a BitmapImage would have to return an Uri, not another BitmapImage:

public object Convert(
    object value, Type targetType, object parameter, CultureInfo culture)
{
    return new Uri(value.ToString());
}
  • Related