将列表值中的字符串绑定为 StaticResource

Binding string from value of list as StaticResource

当我试图从代码隐藏列表中绑定静态资源的名称时,我遇到了一个大问题。

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

在xaml我有

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

我想这样绑定

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

绑定到 TextBlock 效果很好,但绑定到 Image Source 则不行。 当我像

这样绑定到图像源时
Source="{StaticResource Menu1Resource}"

它也能正常工作,但我想从列表中自动绑定。 任何人都可以给我任何提示来解决这个问题吗?;)

据我了解,问题是基于视图模型数据绑定动态创建图像。 这里有几种解决方案:

  1. 您可以将 Menuitem 模型的 Image 属性 更改为 BitmapImage, 并使用在视图模型中创建的 Uri 路径实例创建此 BitmapImage。

        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. 您可以使用一些 IValueConverter 实现 <Image Source="{Binding Value.Image, Converter={StaticResource Path2ImageConverter}}"></Image>.

  3. 创建转换从视图模型接收到 ImageSourse 的路径

问候,

在这种情况下,最简单的解决方案是在您的 Menuitem 中仅使用相对 Uri(就像我在上面的评论中发送的 article 一样)。您可以将工厂放入 shared 并在 W8.1 和 WP8.1 项目中使用它来创建类别集合:

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;
    }
}

并直接绑定:

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

也将 MenuItem 放入 shared

注意:这只是示例,可以通过多种方式解决,但应该可以。希望对您有所帮助 ;)

StaticResource 只有 属性 ResourceKey 但这不是 DependencyProperty,因此您不能在此处使用 Binding。这里的来源当然来自您的视图模型(Value.Image),但该来源不能直接用于图像的 Source 属性。这意味着我们需要在这里使用一些转换器。这可以只是将输入 Value.Image 转换为实际图像源的单向转换器。转换器应在您的视图模型中显示为 属性。应该有一些服务可以帮助通过 ResourceKey 找到实际的图像源。这是您应该遵循的代码:

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

初始化视图模型时,您应该使用接受类型 IFindResourceService 服务的构造函数,在这种情况下您应该可以访问一些 FrameworkElement,它在可视化树中仍然较低与您声明的静态资源相比,我假设 ListBox 可用于在此处构造 FindResourceService

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

现在在XAML中,需要将Image中Binding的Converter设置为视图模型的静态属性:

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

我假设您将 ViewModel 放入命名空间并在 XAML 中将其声明为 local

这一行:

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

您可能正在将 ResourceKey Menu1Resource 设置为 Image,以为您将获得一个 Image 对象。

这样做:

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

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

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

How to get resource from Res Dictionary