I have a ComboBox for which I bound ItemsSource to a enum collection and SelectedItem to a DependencyProperty of the same enum type. So far no problem.
Now I want to display a drawing (associated with each value of the enum collection) instead of the text.
My idea is to use a Converter to translate the value to drawing (and viceversa), using the resource Tag.
in MainWindow.xaml
<Window
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:System="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApp1"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
x:Class="WpfApp1.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<Window.Resources>
<ObjectDataProvider x:Key="Letters" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:Letters"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<local:LetterConverter x:Key="LetterConverter"/>
</Window.Resources>
<Grid>
<ComboBox x:Name="Letter" Grid.Row="0" Width="48" Height="32" ItemsSource="{Binding Source={StaticResource Letters}}" SelectedItem="{Binding Path=SelectedLetter}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Viewbox Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border>
<ContentPresenter Content="{Binding Converter={StaticResource LetterConverter}}"/>
</Border>
</Viewbox>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
in MainWindow.cs
using System;
using System.Windows;
using System.Windows.Data;
namespace WpfApp1
{
/// <summary>
/// Logica di interazione per MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region SelectedLetter property
public Letters SelectedLetter
{
get { return (Letters)GetValue(SelectedLetterProperty); }
set { SetValue(SelectedLetterProperty, value); }
}
public static readonly DependencyProperty SelectedLetterProperty =
DependencyProperty.Register("SelectedLetter", typeof(Letters), typeof(MainWindow), new PropertyMetadata(Letters.E, new PropertyChangedCallback(LetterChanged)));
private static void LetterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MainWindow instance = d as MainWindow;
MessageBox.Show(e.NewValue.ToString());
}
#endregion
public MainWindow()
{
InitializeComponent();
}
}
public enum Letters
{
A, B, C, D, E
}
[ValueConversion(typeof(Letters), typeof(FrameworkElement))]
public class LetterConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
switch ((Letters)value)
{
case Letters.A:
return (FrameworkElement)Application.Current.Resources["A"];
case Letters.B:
return (FrameworkElement)Application.Current.Resources["B"];
case Letters.C:
return (FrameworkElement)Application.Current.Resources["C"];
case Letters.D:
return (FrameworkElement)Application.Current.Resources["D"];
case Letters.E:
return (FrameworkElement)Application.Current.Resources["E"];
default:
throw new ArgumentOutOfRangeException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (((FrameworkElement)value).Tag.ToString().Equals("A"))
return Letters.A;
if (((FrameworkElement)value).Tag.ToString().Equals("B"))
return Letters.B;
if (((FrameworkElement)value).Tag.ToString().Equals("C"))
return Letters.C;
if (((FrameworkElement)value).Tag.ToString().Equals("D"))
return Letters.D;
if (((FrameworkElement)value).Tag.ToString().Equals("E"))
return Letters.E;
throw new ArgumentOutOfRangeException();
}
}
}
in App.xaml
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Canvas x:Key="A" Width="24" Height="24" Tag="A">
<Path Width="24" Height="24" Data="M11,7H13A2,2 0 0,1 15,9V17H13V13H11V17H9V9A2,2 0 0,1 11,7M11,9V11H13V9H11M12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="B" Width="24" Height="24" Tag="B">
<Path Width="24" Height="24" Data="M15,10.5C15,11.3 14.3,12 13.5,12C14.3,12 15,12.7 15,13.5V15A2,2 0 0,1 13,17H9V7H13A2,2 0 0,1 15,9V10.5M13,15V13H11V15H13M13,11V9H11V11H13M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="C" Width="24" Height="24" Tag="C">
<Path Width="24" Height="24" Data="M11,7H13A2,2 0 0,1 15,9V10H13V9H11V15H13V14H15V15A2,2 0 0,1 13,17H11A2,2 0 0,1 9,15V9A2,2 0 0,1 11,7M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="D" Width="24" Height="24" Tag="D">
<Path Width="24" Height="24" Data="M9,7H13A2,2 0 0,1 15,9V15A2,2 0 0,1 13,17H9V7M11,9V15H13V9H11M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="E" Width="24" Height="24" Tag="E">
<Path Width="24" Height="24" Data="M9,7H15V9H11V11H15V13H11V15H15V17H9V7M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
</Application.Resources>
</Application>
At this point, once an element is selected from the drop-list, it becomes smaller and is no longer visible.
Any suggestions?
Set the x:Shared attribute of your resources to false:
<Canvas x:Key="A" Width="24" Height="24" Tag="A" x:Shared="False">
<Path Width="24" Height="24" Data="M11,7H13A2,2 0 0,1 15,9V17H13V13H11V17H9V9A2,2 0 0,1 11,7M11,9V11H13V9H11M12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="B" Width="24" Height="24" Tag="B" x:Shared="False">
<Path Width="24" Height="24" Data="M15,10.5C15,11.3 14.3,12 13.5,12C14.3,12 15,12.7 15,13.5V15A2,2 0 0,1 13,17H9V7H13A2,2 0 0,1 15,9V10.5M13,15V13H11V15H13M13,11V9H11V11H13M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="C" Width="24" Height="24" Tag="C" x:Shared="False">
<Path Width="24" Height="24" Data="M11,7H13A2,2 0 0,1 15,9V10H13V9H11V15H13V14H15V15A2,2 0 0,1 13,17H11A2,2 0 0,1 9,15V9A2,2 0 0,1 11,7M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="D" Width="24" Height="24" Tag="D" x:Shared="False">
<Path Width="24" Height="24" Data="M9,7H13A2,2 0 0,1 15,9V15A2,2 0 0,1 13,17H9V7M11,9V15H13V9H11M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
<Canvas x:Key="E" Width="24" Height="24" Tag="E" x:Shared="False">
<Path Width="24" Height="24" Data="M9,7H15V9H11V11H15V13H11V15H15V17H9V7M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" Fill="Black"/>
</Canvas>
If you don't, the same Canvas element is reused and a visual element can only appear once in the visual tree.
How would I change the vector color from the code behind? Code behind in this example doesn't work.
From the Resource Dictionary..
<VisualBrush x:Key="Alarm-Light">
<VisualBrush.Visual>
<Canvas>
<Path Data="M12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22M12,7L7,12H10V16H14V12H17L12,7Z" Fill="#424242" />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
From the Xaml..
<TextBlock x:Name="TextConnect" Width="20">
<Rectangle x:Name="AlarmLight" Fill="{StaticResource Alarm-Light}" Height="16" Width="16" />
Code Behind...
private void Connection_Check()
{
var brush = LocalSystem.Connected ? new SolidColorBrush(Colors.GreenYellow) : new SolidColorBrush(Colors.DimGray);
AlarmLight.Fill = brush;
}
This works:
<VisualBrush x:Key="Alarm-Light">
<VisualBrush.Visual>
<Canvas>
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=AlarmFill}" Data="M12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22M12,7L7,12H10V16H14V12H17L12,7Z" />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
With this code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
AlarmFill = new SolidColorBrush(Colors.Blue);
}
/// <summary>
/// Gets or Sets AlarmFill Dependency Property
/// </summary>
public Brush AlarmFill
{
get { return (Brush)GetValue(AlarmFillProperty); }
set { SetValue(AlarmFillProperty, value); }
}
public static readonly DependencyProperty AlarmFillProperty =
DependencyProperty.Register("AlarmFill", typeof(Brush), typeof(MainWindow), new PropertyMetadata(null));
}
Or this one:
<VisualBrush x:Key="Alarm-Light">
<VisualBrush.Visual>
<Canvas>
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.AlarmFill}" Data="M12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22M12,7L7,12H10V16H14V12H17L12,7Z" />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
With this code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
AlarmFill = new SolidColorBrush(Colors.Blue);
}
/// <summary>
/// Gets or Sets AlarmFill Dependency Property
/// </summary>
public Brush AlarmFill
{
get { return (Brush)GetValue(AlarmFillProperty); }
set { SetValue(AlarmFillProperty, value); }
}
public static readonly DependencyProperty AlarmFillProperty =
DependencyProperty.Register("AlarmFill", typeof(Brush), typeof(MainWindow), new PropertyMetadata(null));
}
My application has some menu buttons, and the button shows the current selection, for example, if user selects "Red", the button image is "Red pen". I prepare XAML files for the button image, like this.
<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SmartScreen">
<DrawingBrush x:Key="sample_test" Stretch="Uniform">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FF000000" Geometry="F1 M 87.7748,67.8528L 87.7748,54.9208C 87.7748,52.9101 86.1441,51.2781 84.1375,51.2781L 61.3575,51.2781L 61.3575,24.4635L 63.1001,24.4635C 64.7948,24.4635 66.1788,23.0808 66.1788,21.3861L 66.1788,8.06213C 66.1788,6.36613 64.7948,4.9888 63.1001,4.9888L 49.7748,4.9888C 48.0801,4.9888 46.6988,6.36613 46.6988,8.06213L 46.6988,21.3861C 46.6988,23.0808 48.0801,24.4635 49.7748,24.4635L 51.5095,24.4635L 51.5095,51.2781L 28.7348,51.2781C 27.2241,51.2781 25.9228,52.2061 25.3735,53.5115C 26.0281,53.4501 26.6948,53.4168 27.3601,53.4168C 37.6975,53.4168 46.2041,61.3808 47.0895,71.4915L 84.1375,71.4915C 86.1441,71.4915 87.7748,69.8595 87.7748,67.8528 Z "/>
<GeometryDrawing Brush="#FF000000" Geometry="F1 M 84.138,84.7019C 86.1447,84.7019 87.7753,83.0739 87.7753,81.0672L 87.7753,79.0565C 87.7753,77.0365 86.1447,75.4139 84.138,75.4139L 47.046,75.4139C 46.666,78.8512 45.402,82.0219 43.4873,84.7019L 84.138,84.7019 Z "/>
<GeometryDrawing Brush="#FF000000" Geometry="F1 M 27.3607,85.9973C 20.302,85.9973 14.5847,80.2747 14.5847,73.2253C 14.5847,66.1707 20.302,60.4467 27.3607,60.4467C 34.4193,60.4467 40.134,66.1707 40.134,73.2253C 40.134,80.2747 34.4193,85.9973 27.3607,85.9973 Z M 27.3607,56.9733C 18.386,56.9733 11.114,64.2467 11.114,73.2253C 11.114,82.1933 18.386,89.4693 27.3607,89.4693C 36.3313,89.4693 43.6113,82.1933 43.6113,73.2253C 43.6113,64.2467 36.3313,56.9733 27.3607,56.9733 Z "/>
<GeometryDrawing Brush="{Binding Path=SampleColor}" Geometry="F1 M 35.8893,71.2825L 29.3013,71.2825L 29.3013,63.6785C 29.3013,62.6105 28.4333,61.7465 27.3613,61.7465C 26.288,61.7465 25.4253,62.6105 25.4253,63.6785L 25.4253,72.2132C 25.4253,72.3905 25.4507,72.5559 25.4933,72.7199C 25.4507,72.8785 25.4253,73.0425 25.4253,73.2252C 25.4253,74.2932 26.288,75.1572 27.3613,75.1572L 35.8893,75.1572C 36.964,75.1572 37.8293,74.2932 37.8293,73.2252C 37.8293,72.1532 36.964,71.2825 35.8893,71.2825 Z "/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</ResourceDictionary>
Put this file (named 'sample_test.xaml') to the ResourceDictionary of Applicaton.Resources.
<Application x:Class="SmartScreen.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="sample_test.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MainWindow.xaml is following,
<Window x:Class="SmartScreen.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:Test">
<Grid Loaded="Grid_Loaded">
<Label Name="label1" Width="100" Height="100" HorizontalAlignment="Center" VerticalAlignment="Center"
Background="{DynamicResource sample_test}"
/>
<Label Name="label2" Width="100" Height="100" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="100,0">
<Label.Background>
<DrawingBrush Stretch="Uniform">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FF000000" Geometry="F1 M 87.7748,67.8528L 87.7748,54.9208C 87.7748,52.9101 86.1441,51.2781 84.1375,51.2781L 61.3575,51.2781L 61.3575,24.4635L 63.1001,24.4635C 64.7948,24.4635 66.1788,23.0808 66.1788,21.3861L 66.1788,8.06213C 66.1788,6.36613 64.7948,4.9888 63.1001,4.9888L 49.7748,4.9888C 48.0801,4.9888 46.6988,6.36613 46.6988,8.06213L 46.6988,21.3861C 46.6988,23.0808 48.0801,24.4635 49.7748,24.4635L 51.5095,24.4635L 51.5095,51.2781L 28.7348,51.2781C 27.2241,51.2781 25.9228,52.2061 25.3735,53.5115C 26.0281,53.4501 26.6948,53.4168 27.3601,53.4168C 37.6975,53.4168 46.2041,61.3808 47.0895,71.4915L 84.1375,71.4915C 86.1441,71.4915 87.7748,69.8595 87.7748,67.8528 Z "/>
<GeometryDrawing Brush="#FF000000" Geometry="F1 M 84.138,84.7019C 86.1447,84.7019 87.7753,83.0739 87.7753,81.0672L 87.7753,79.0565C 87.7753,77.0365 86.1447,75.4139 84.138,75.4139L 47.046,75.4139C 46.666,78.8512 45.402,82.0219 43.4873,84.7019L 84.138,84.7019 Z "/>
<GeometryDrawing Brush="#FF000000" Geometry="F1 M 27.3607,85.9973C 20.302,85.9973 14.5847,80.2747 14.5847,73.2253C 14.5847,66.1707 20.302,60.4467 27.3607,60.4467C 34.4193,60.4467 40.134,66.1707 40.134,73.2253C 40.134,80.2747 34.4193,85.9973 27.3607,85.9973 Z M 27.3607,56.9733C 18.386,56.9733 11.114,64.2467 11.114,73.2253C 11.114,82.1933 18.386,89.4693 27.3607,89.4693C 36.3313,89.4693 43.6113,82.1933 43.6113,73.2253C 43.6113,64.2467 36.3313,56.9733 27.3607,56.9733 Z "/>
<GeometryDrawing Brush="{Binding SampleColor}" Geometry="F1 M 35.8893,71.2825L 29.3013,71.2825L 29.3013,63.6785C 29.3013,62.6105 28.4333,61.7465 27.3613,61.7465C 26.288,61.7465 25.4253,62.6105 25.4253,63.6785L 25.4253,72.2132C 25.4253,72.3905 25.4507,72.5559 25.4933,72.7199C 25.4507,72.8785 25.4253,73.0425 25.4253,73.2252C 25.4253,74.2932 26.288,75.1572 27.3613,75.1572L 35.8893,75.1572C 36.964,75.1572 37.8293,74.2932 37.8293,73.2252C 37.8293,72.1532 36.964,71.2825 35.8893,71.2825 Z "/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Label.Background>
</Label>
</Grid>
</Window>
Finnally, the view model of MainWindow should has the property named "SampleColor" like this;
namespace Sample
{
...
public class MainWindowViewModel
{
public Brush SampleColor
{
get
{
return Brushes.Red;
}
}
}
}
Result, the label named "label2" shows the red parts, but "label1" doesn't.
I don't know how to tell the DataContext to the resource in the ResourceDictionary.
This is very simular, but DrawinBrush has no DataContext.