将列表值中的字符串绑定为 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}"
它也能正常工作,但我想从列表中自动绑定。
任何人都可以给我任何提示来解决这个问题吗?;)
据我了解,问题是基于视图模型数据绑定动态创建图像。
这里有几种解决方案:
您可以将 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();
}
}
您可以使用一些 IValueConverter
实现 <Image Source="{Binding Value.Image, Converter={StaticResource Path2ImageConverter}}"></Image>
.
创建转换从视图模型接收到 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
当我试图从代码隐藏列表中绑定静态资源的名称时,我遇到了一个大问题。
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}"
它也能正常工作,但我想从列表中自动绑定。 任何人都可以给我任何提示来解决这个问题吗?;)
据我了解,问题是基于视图模型数据绑定动态创建图像。 这里有几种解决方案:
您可以将 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(); } }
您可以使用一些
IValueConverter
实现<Image Source="{Binding Value.Image, Converter={StaticResource Path2ImageConverter}}"></Image>
. 创建转换从视图模型接收到 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