【问题标题】:Binding string from value of list as StaticResource将列表值中的字符串绑定为 StaticResource
【发布时间】:2015-10-18 18:37:50
【问题描述】:

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

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

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

【问题讨论】:

  • 你能展示你在 Resources/Icons.xaml 中有什么吗?是否有图像或一些向量(路径)?
  • xaml 资源中将本地资源(文件)中的图像存储为 BitmapImage 的原因是什么?您可以将资源作为 Uri 添加到模型中,而无需额外的 BitmapImages 和转换器。就像here
  • 因为我将资源存储在 .shared 中,并且我想在 W8.1 和 WP8.1 项目之间使用它。是不是个好主意?
  • 我在下面放了更长的答案。

标签: c# wpf xaml windows-phone-8.1


【解决方案1】:

在这一行:

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
}

最后是&lt;Image Source="{Binding Value.Image}"/&gt;

How to get resource from Res Dictionary

【讨论】:

    【解决方案2】:

    据我所知,问题是基于视图模型数据绑定动态创建图像。 以下是几种解决方案:

    1. 您可以将 Menuitem 模型的 Image 属性更改为 BitmapImage, 并使用在 viewmodel 中创建的 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 实现&lt;Image Source="{Binding Value.Image, Converter={StaticResource Path2ImageConverter}}"&gt;&lt;/Image&gt; 创建从视图模型接收的路径转换到ImageSourse。

    问候,

    【讨论】:

    • 你的意思是,我必须从资源文件中获取 Uri 到 viewmodel,然后直接绑定到图像?
    • @DominikMiedziński 是的。
    【解决方案3】:

    在这种情况下,最简单的解决方案是在您的 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

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

    【讨论】:

      【解决方案4】:

      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

      【讨论】:

        猜你喜欢
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 2014-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多