如何为 DynamicResource 使用 ViewModel 变量?

Mel*_*eir 5 wpf xaml

这不是 MahApps.Metro 特定的,但这恰好是我正在使用的。我有一组 ViewModel,它们有一个string属性,表示要使用资源 XAML 文件中的哪个图标。

public class CommandViewModel : ViewModel
{
    public CommandViewModel(string displayName, ICommand command, string icon)
    {
        if (command == null)
            throw new ArgumentNullException("command");

        DisplayName = displayName;
        Command = command;
        Icon = icon;
    }

    public ICommand Command { get; private set; }
    public string Icon { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Icon最终会成为 MahApps.Metro.Resources 中的“appbar_add”之类的东西。这些是在 Icons.xaml 文件中定义的。

我如何在我的ItemTemplate这样的文件中写出正确的资源显示。我要么在执行时出错(不是在编辑/构建时),要么根本没有图标。

“无图标”XAML 如下所示:

<ItemsControl ItemsSource="{Binding}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Rectangle Width="20" Height="20">
                    <Rectangle.Fill>
                        <VisualBrush Visual="{DynamicResource {Binding Path=Icon}}" />
                    </Rectangle.Fill>
                </Rectangle>
                <TextBlock Margin="15,6">                            
                    <Hyperlink Command="{Binding Path=Command}">
                        <TextBlock Text="{Binding Path=DisplayName}" />
                    </Hyperlink>
                </TextBlock>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
Run Code Online (Sandbox Code Playgroud)

我导致错误的尝试是使用StaticResource,我认为这从根本上是不正确的。

我应该如何将该Icon属性作为我想要的资源的名称?

编辑

被要求更多的代码,所以这里是一个什么样的例子的工作:

<Rectangle Width="20" Height="20">
    <Rectangle.Fill>
        <VisualBrush Visual="{StaticResource appbar_add}" />
    </Rectangle.Fill>
</Rectangle>
Run Code Online (Sandbox Code Playgroud)

我需要做的是让“appbar_add”成为我的 ViewModel 上的一个属性的值——Icon上面的属性。

资源位于单独文件 (Icon.xaml) 中的 ResourceDictionary 中,如下所示:

<Canvas x:Key="appbar_add" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
    <Path Width="38" Height="38" Canvas.Left="19" Canvas.Top="19" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="F1 M 35,19L 41,19L 41,35L 57,35L 57,41L 41,41L 41,57L 35,57L 35,41L 19,41L 19,35L 35,35L 35,19 Z "/>
</Canvas>
Run Code Online (Sandbox Code Playgroud)

Ayy*_*ian 2

您可以使用转换器来完成这项工作。参考下面的代码。我有两种样式可以在 Icon.xaml 中将 + 符号制成红色或黑色。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Canvas x:Key="appbar_add_Black" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
        <Path Width="38" Height="38" Canvas.Left="19" Canvas.Top="19" Stretch="Fill" Fill="Black" Data="F1 M 35,19L 41,19L 41,35L 57,35L 57,41L 41,41L 41,57L 35,57L 35,41L 19,41L 19,35L 35,35L 35,19 Z "/>
    </Canvas>
    <Canvas x:Key="appbar_add_Red" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
        <Path Width="38" Height="38" Canvas.Left="19" Canvas.Top="19" Stretch="Fill" Fill="Red" Data="F1 M 35,19L 41,19L 41,35L 57,35L 57,41L 41,41L 41,57L 35,57L 35,41L 19,41L 19,35L 35,35L 35,19 Z "/>
    </Canvas>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)

请参阅查看代码。

<Window.Resources>
    <local:IconConverter x:Key="conv"/>
</Window.Resources>
<Grid>
    <Rectangle Width="20" Height="20">
        <Rectangle.Fill>
            <VisualBrush Visual="{Binding Icon,Converter={StaticResource conv}}" />
        </Rectangle.Fill>
    </Rectangle>
</Grid>
Run Code Online (Sandbox Code Playgroud)

视图模型

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new CommandViewModel("Red");
    }
}

public class CommandViewModel :INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
    public CommandViewModel(string icon)
    { 
        Icon = icon;
    }

    private string icon;

    public string Icon
    {
        get { return icon; }
        set { icon = value; }
    }    
}

class IconConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string str = (string)value;
        ResourceDictionary myResourceDictionary = new ResourceDictionary();
        myResourceDictionary.Source =
            new Uri("Icon.xaml",
                UriKind.Relative);
        if (str.Equals("Black"))
        {              
            return myResourceDictionary["appbar_add_Black"];
        }
        else
        {
            return myResourceDictionary["appbar_add_Red"];
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)