Столкнулся с интересной задачей. Есть некоторая коллекция данных, которую надо отобразить в ItemsControl. У элементов данных есть два свойства: первое просто текст, а второе имя ресурса с картинкой которую необходимо показать. Т.е. в зависимости от данных в модели должен подгружаться тот или иной ресурс. Поискав решение быстро наткнулся на применение конвертора который ищет ресурс по имени следующим способом:
Но это не работает, если ресурсы подгружены не в приложение, а например, в окно или контрол. Под катом интересный метод, который позволяет получить доступ к ресурсу где бы он не находился, главное, чтобы был доступен контролу.
В рамках примера, я буду использовать простой класс с двумя свойствами:
Как я уже сказал, таким образом надо поступать, если в конверторе нельзя просто извлечь ресурсы из Application. Так, кстати, можно и другие свойства задавать, необязательно привязку к ресурсам.
return Application.Current.FindResource(resourceName) as BitmapImage;
Но это не работает, если ресурсы подгружены не в приложение, а например, в окно или контрол. Под катом интересный метод, который позволяет получить доступ к ресурсу где бы он не находился, главное, чтобы был доступен контролу.
В рамках примера, я буду использовать простой класс с двумя свойствами:
public class Model { public string Title { get; set; } public string ResourceName { get; set; } }Вот разметка формы:
<Window x:Class="WpfApplication4.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApplication4" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <BitmapImage x:Key="plus" UriSource="plus.png" /> <BitmapImage x:Key="delete" UriSource="delete.png" /> <local:NameToStyleConverter x:Key="NameToStyleConverter" /> </Window.Resources> <Grid> <ItemsControl x:Name="icDemo"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Style="{Binding ResourceName,Converter={StaticResource NameToStyleConverter}}" /> <TextBlock Text="{Binding Title}" /> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid> </Window>А вот заполнение данными списка при загрузке:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { List<Model> items = new List<Model>(); items.Add(new Model() { Title = "Один", ResourceName = "plus" }); items.Add(new Model() { Title = "Два", ResourceName = "plus" }); items.Add(new Model() { Title = "Три", ResourceName = "delete" }); items.Add(new Model() { Title = "Четыре", ResourceName = "plus" }); items.Add(new Model() { Title = "Пять", ResourceName = "delete" }); icDemo.ItemsSource = items; } }Как можно видеть из разметки, у контрола Image свойство Source не присваивается, а присваивается... Стиль! Ну а дальше все просто, получая имя ресурсы, мы конвертором создаем динамически стиль, в котором свойству Source присваиваем DynamicResource. Вот так:
public class NameToStyleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Style result = null; var name = value?.ToString(); if (!string.IsNullOrWhiteSpace(name)) { result = new Style(typeof(Image)); var dynamicResource = new DynamicResourceExtension(name); var setter = new Setter() { Property = Image.SourceProperty, Value = dynamicResource }; result.Setters.Add(setter); } return result; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }Ну и вот так это выглядит:
Как я уже сказал, таким образом надо поступать, если в конверторе нельзя просто извлечь ресурсы из Application. Так, кстати, можно и другие свойства задавать, необязательно привязку к ресурсам.
как то была подобная задача, в программе использовал локализацию через динамические ресурсы, для быстрой смены языка. Да и вообще все строковые константы приятнее хранить в ResourceDirctiory, удобно разбивать на файлы, редактировать, искать по сравнению с resx файлами.
ОтветитьУдалитьАлексей, посмотрел видео с Вашим уроком (Уроки WPF. Таблицы и списки). Теперь ломаю голову как сделать динамическое расширение списка. Например передавая день месяца и его соответствие дню недели. (lbName.ItemsSource = new[] { new { FirstColumn = DayOfMonth[], SecondColumn = DayWeekName[] } };)
ОтветитьУдалить