How can I specify resources in an MVVM view model?

后端 未结 2 1176
天命终不由人
天命终不由人 2021-02-03 10:26

Suppose I want to show list of objects where each object should have a name and a suitable image (for example MenuItems with Icons, or buttons with text and image).

All

相关标签:
2条回答
  • 2021-02-03 10:45

    The first workaround you mention can be found here: Binding a datacontext string property to a StaticResource key

    I tried to use the second work around you mention ( http://sweux.com/blogs/psampaio/index.php/2009/06/16/using-data-binding-with-static-resources-in-wpf/), but I never got it working. It throwed an ArgumentNullException since the DataContext was null. I think this had something to do with the fact that I was using a DataTemplate to create my View from my ViewModel, and somehow the DataContext was not set before the ProvideValue method was called (in the example on that page, the DataContext is set in the .xaml.vb class).

    So, I started looking for a workaround and found one which also involves a converter, but this one finds the resource through a FrameworkElement method instead of poking around Application.Current. The one I found is detailed here:

    http://drwpf.com/blog/2007/08/18/can-my-value-converter-access-the-target-of-the-binding/

    I'll copy the relevant information here:

    It involves a ValueConverter implementing the interface IMultiValueConverter, to have access to the control on which the binding is set.

    The code for the Convert method is the following:

    public object Convert(object[] values, Type targetType, 
        object parameter, CultureInfo culture)
    {
        FrameworkElement targetObject = values[0] as FrameworkElement;
    
        if (targetObject == null)
        {
            return DependencyProperty.UnsetValue;
        }
        return targetObject.TryFindResource(values[1]);
    }
    

    And the XAML for a content control would look like this:

    <ContentControl>
      <ContentControl.Content>
        <MultiBinding Converter="{StaticResource Converter}">
          <MultiBinding.Bindings>
            <Binding RelativeSource="{RelativeSource Self}" />
            <Binding Path="ResourceKey" />
          </MultiBinding.Bindings>
        </MultiBinding>
      </ContentControl.Content>
    </ContentControl>
    

    And the XAML for an Image is the following:

    <Image Height="16" Width="16">
        <Image.Source>
            <MultiBinding Converter="{StaticResource Converter}">
                <MultiBinding.Bindings>
                    <Binding RelativeSource="{RelativeSource Self}" />
                    <Binding Path="ResourceKey" />
                </MultiBinding.Bindings>
            </MultiBinding>
        </Image.Source>
    </Image>
    

    Works like a charm :D

    0 讨论(0)
  • 2021-02-03 11:04

    There's a bug in custom MarkupExtensions that doesn't allow you to use them in an attribute like that.

    Workaround 1: Declare the attribute as an element, like so:

    <Image>
        <Image.Source>
            <local:BindableStaticResource Binding={Binding Icon}" />
        </Image.Source>
    </Image>
    

    Workaround 2: If you precompile the MarkupExtension by putting it in another assembly and referencing it, then it works again. This might be why you're seeing it work in the main window, but not in your DataTemplate.

    0 讨论(0)
提交回复
热议问题