1

I have a big problem when i'm trying to bind name of static resource from list in code behind.

public IDictionary<int, Menuitem> Categories = new Dictionary<int, Menuitem>();
Categories.Add(1, new Menuitem() { Name = "Menu1", Image = "Menu1Resource" });
list.ItemsSource = Categories;

in xaml I have

<Page.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Resources/Icons.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Page.Resources>

and i want to bind like this

<ListView Padding="20 0" Grid.Row="1" x:Name="list" >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Border Background="#53921D" Margin="0 0 0 10" Padding="15">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="1*"/>
                                <ColumnDefinition Width="9*"/>
                            </Grid.ColumnDefinitions>
                            <Image Source="{StaticResource ResourceKey={Binding Value.Image}}"/>
                            <TextBlock Grid.Column="1" Foreground="White" Text="{Binding Value.Name}" HorizontalAlignment="Center" FontSize="30" VerticalAlignment="Center"/>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ListView.ItemTemplate>
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                </Style>
            </ListView.ItemContainerStyle>
</ListView>

Binding to TextBlock works well, but to Image Source doesn't. when I Bind to image source like

Source="{StaticResource Menu1Resource}"

it working too, but i want to bind automatically from list. Can anyone give my any tip to solve this problem?;)

4 Answers4

1

As I can understand the problem is to create the Image dynamicly based on the viewmodel databinding. Here are several solutions:

  1. You can change the Image propery of Menuitem model to be a BitmapImage, and create this BitmapImage using instance of Uri path created in viewmodel.

        private void Load(object o)
    {
        var name = _mFileProvider.GetFileName();
        if(string.IsNullOrEmpty(name)) return;
        ImageSourceBmp = null;
        ZoomOriginal();
        ImageSourceBmp = new BitmapImage(new Uri(name));
    }
    
    public BitmapImage ImageSourceBmp   
    {
        get { return _imageSourceBmp; }
        set
        {
            _imageSourceBmp = value;
            OnPropertyChanged();
        }
    }
    
  2. You can create convert the path receive from the viewmodel int the ImageSourse using some IValueConverter implementation <Image Source="{Binding Value.Image, Converter={StaticResource Path2ImageConverter}}"></Image>.

regards,

Ilan
  • 2,762
  • 1
  • 13
  • 24
1

In this case, the easiest solution is to use just relative Uri in your Menuitem (like in article I sent above in comment). You can put factory into shared and use it in W8.1 and WP8.1 projects to create collection of Categories:

public class MenuItem
{
    public string Name { get; set; }

    public Uri ImageUri { get; set; }
}

public class CategoriesFactory
{
    public static IDictionary<int, MenuItem> GetCategories()
    {
        var categories = new Dictionary<int, MenuItem>();

        categories.Add(1, new MenuItem() { Name = "Menu1", ImageUri = new Uri("Icons/image.png", UriKind.RelativeOrAbsolute) });

        //add more categories

        return categories;
    }
}

and bind directly:

<Image Source="{Binding Value.ImageUri}"/>

Put MenuItem into shared too.

Note: it's only sample, it can be solved in many ways, but It should work. Hope it helps ;)

marcinax
  • 1,067
  • 7
  • 10
1

StaticResource has only property ResourceKey but this is not a DependencyProperty, so you cannot use Binding here. The source here is of course from your view-model (the Value.Image) but that source cannot be used directly for the Source property of an Image. That means we need to use some Converter here. This can be just a one-way converter to convert the input Value.Image to the actual image source. The Converter should be exposed as a property in your view-model. There should be some service to help find the actual image source via the ResourceKey. Here is the code you should follow:

public interface IFindResourceService {
    object FindResource(object resourceKey);
}
public class FindResourceService : IFindResourceService {
    FrameworkElement _element;
    public FindResourceService(FrameworkElement startElement){
       _element = startElement;
    }
    public object FindResource(object resourceKey){
       return _element.FindResource(resourceKey);
    }
}

//the converter
public class ResourceKeyToResourceConverter : IValueConverter {
    public IFindResourceService FindResourceService {get;set;}
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture){
        if(FindResourceService == null) return null;
        return FindResourceService.FindResource(value);
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
       throw new NotImplementedException();
    }
}

//your view-model, suppose it inherits from some base view-model
//or implements INotifyPropertyChanged directly ...
public class ViewModel : BaseVM {
    public ViewModel(IFindResourceService _service){
        ResourceKeyToResource.FindResourceService = _service;            
    }
    public static ResourceKeyToResourceConverter ResourceKeyToResource = new ResourceKeyToResourceConverter();
    //... define other properties, members for your view-model normally
    //...
}

When initializing the view-model, you should use the constructor accepting a service of type IFindResourceService, in that context you should have access to some FrameworkElement which is still lower in the visual tree compared to the static resource you declared, I assume the ListBox can be used to construct a FindResourceService here:

public MainWindow(){
   InitializeComponent();
   var vm = new ViewModel(new FindResourceService(list));
   DataContext = vm;
}

Now in XAML, you need to set the Converter of the Binding in Image to the static property of the view model:

<Image Source="{Binding Value.Image, 
                Converter={x:Static local:ViewModel.ResourceKeyToResource}}"/>

I assume you put the ViewModel in a namespace and declared that as local in XAML.

King King
  • 61,710
  • 16
  • 105
  • 130
1

In this line :

Categories.Add(1, new Menuitem() { Name = "Menu1", Image = "Menu1Resource" });

You are setting probably ResourceKey Menu1Resource to Image thinking that you will get an Image object.

Do this :

Categories.Add(1, new Menuitem() { Name = "Menu1", Image = _getImgFromResKey("Menu1Resource") });

Image _getImgFromResKey(string key)
{
   //access resource from res dictionary
}

and finally <Image Source="{Binding Value.Image}"/>

How to get resource from Res Dictionary

Community
  • 1
  • 1
AnjumSKhan
  • 9,647
  • 1
  • 26
  • 38