C# SolidColorBrush to my Converter Class - c#

i have an object of the type SolidColorBrush and it holds
a SolidColorBrush.
Now i have a converter for my dataGrid which is binded to a list.
Each row in this dataGrid will be colored by the Converter i have.
All is working fine, but how can i return my SolidColorBrush object instead of an static "Brushes.Red" for example.
My converter:
[ValueConversion(typeof(MainWindow.eErrorLevel), typeof(Brush))]
public class TypeToColourConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
MainWindow.eErrorLevel errorLevel = (MainWindow.eErrorLevel)value;
switch (errorLevel)
{
case MainWindow.eErrorLevel.Information:
return Brushes.Red;
case MainWindow.eErrorLevel.Warning:
return Brushes.Yellow;
case MainWindow.eErrorLevel.Error:
return Brushes.Red;
}
return Brushes.Gray;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
My converter is not in the MainWindow, if thats important
And My SolidColorBrush object in my MainWindow which is public:
public CurrentColor CurrentColors = new CurrentColor();
public class CurrentColor
{
public SolidColorBrush ERROR { get; set; }
public SolidColorBrush WARNING { get; set; }
public SolidColorBrush INFORMATION { get; set; }
}
EDIT: my brushes can be dynamically set by the user itself
EDIT2: now its working thanks guys :)

Assuming that these colours won't change at runtime, you could declare your brushes as resources above your converter and add properties to your converter for each brush as follows:
Amend your converter to:
[ValueConversion(typeof(MainWindow.eErrorLevel), typeof(Brush))]
public class TypeToColourConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
MainWindow.eErrorLevel errorLevel = (MainWindow.eErrorLevel)value;
switch (errorLevel)
{
case MainWindow.eErrorLevel.Information:
return Error;
case MainWindow.eErrorLevel.Warning:
return Warning;
case MainWindow.eErrorLevel.Error:
return Information;
}
return Normal;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
public Brush Normal { get; set; }
public Brush Error { get; set; }
public Brush Warning { get; set; }
public Brush Information { get; set; }
}
Amend your XAML (wherever your converter is added):
<SolidColorBrush x:Key="Normal" Color="#FFAAAAAA"/>
<SolidColorBrush x:Key="Error" Color="#FFFF0000"/>
<SolidColorBrush x:Key="Warning" Color="#FF00FF00"/>
<SolidColorBrush x:Key="Information" Color="#FF0000FF"/>
<local:TypeToColourConverter x:Key="TypeToColourConverter" Normal="{StaticResource Normal}" Error="{StaticResource Error}" Warning="{StaticResource Warning}" Information="{StaticResource Information}" />
This is very 'designer-friendly' (i.e. all these colours can then be changed in Blend) and easy to maintain.
Hope it helps.

Like I said in my comments, here's an example, passing it as converterparameter, there are probably alternatives:
XAML
<Window x:Class="WpfApplicationTestColorConverter.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:WpfApplicationTestColorConverter"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:ErrorColors x:Key="Colors" />
<local:TypeToColourConverter x:Key="ColorConverter" />
</Window.Resources>
<Grid>
<ListBox x:Name="ListBox1" ItemsSource="{Binding MyObjects}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Title}"
Background="{Binding ErrorLevel,
Converter={StaticResource ColorConverter},
ConverterParameter={StaticResource Colors}}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Code behide
public partial class MainWindow : Window
{
public ObservableCollection<MyObject> MyObjects { get; } = new ObservableCollection<MyObject>();
public MainWindow()
{
InitializeComponent();
DataContext = this;
// find the (static)resource
var colors = (ErrorColors)FindResource("Colors");
colors.ERROR = new SolidColorBrush(Colors.Red);
colors.WARNING = new SolidColorBrush(Colors.Orange);
colors.INFORMATION = new SolidColorBrush(Colors.Lime);
// Add objects to the list
MyObjects.Add(new MyObject { Title = "This is an error", ErrorLevel = ErrorLevel.Error });
MyObjects.Add(new MyObject { Title = "This is a warning", ErrorLevel = ErrorLevel.Warning });
MyObjects.Add(new MyObject { Title = "This is information", ErrorLevel = ErrorLevel.Information });
}
}
The Converter
[ValueConversion(typeof(ErrorLevel), typeof(Brush))]
public class TypeToColourConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (!(value is ErrorLevel))
return Brushes.Gray;
if (!(parameter is ErrorColors))
return Brushes.Gray;
var lvl = (ErrorLevel)value;
var currentColor = (ErrorColors)parameter;
switch (lvl)
{
case ErrorLevel.Information:
return currentColor.INFORMATION;
case ErrorLevel.Warning:
return currentColor.WARNING;
case ErrorLevel.Error:
return currentColor.ERROR;
}
return Brushes.Gray;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
public class ErrorColors
{
public SolidColorBrush ERROR { get; set; }
public SolidColorBrush WARNING { get; set; }
public SolidColorBrush INFORMATION { get; set; }
}
public enum ErrorLevel
{
Error,
Warning,
Information
}
public class MyObject
{
public string Title { get; set; }
public ErrorLevel ErrorLevel { get; set; }
}
Results:

Related

IMarkupExtension with bindable properties

I've created an IMarkupExtension for an ImageSource which gets a specified symbol from a specified font and displays it in a specified color with a specified height. Most of the times the icon name is static and I write into the XAML directly. But sometimes there are lists of things that have a property which determines which icon should be used. For this case it is necessary that the icon name is bindable.
Here is (more or less) the current state of my FontImageExtension:
[ContentProperty(nameof(IconName))]
public class FontImageExtension : IMarkupExtension<ImageSource>
{
private readonly IconFontService iconFontService;
[TypeConverter(typeof(FontSizeConverter))]
public double Size { get; set; } = 30d;
public string IconName { get; set; }
public Color Color { get; set; }
public string FontFamily { get; set; }
public FontImageExtension()
{
iconFontService = SomeKindOfContainer.Resolve<IconFontService>();
}
public ImageSource ProvideValue(IServiceProvider serviceProvider)
{
if (string.IsNullOrEmpty(IconName))
return null;
IconFont iconFont = iconFontService.GetIconFont();
if (iconFont == null)
return null;
string glyphCode = iconFont.GetGlyphCode(IconName);
if (string.IsNullOrEmpty(glyphCode))
return null;
FontImageSource fontImageSource = new FontImageSource()
{
FontFamily = iconFont.GetPlatformLocation(),
Glyph = glyphCode,
Color = this.Color,
Size = this.Size,
};
return fontImageSource;
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return ProvideValue(serviceProvider);
}
}
Most of the time I use it like this in XAML (which already works perfectly):
<Image Source="{m:FontImage SomeIcon, Color=Black, Size=48}"/>
But for dynamic UI (e.g. lists or something) I need it like this:
<CollectionView ItemsSource={Binding SomeCollection}">
<CollectionView.ItemTemplate>
<StackLayout>
<Image Source="{m:FontImage IconName={Binding ItemIcon}, Color=Black, Size=48}"/>
<Label Text="{Binding ItemText}"/>
</StackLayout>
</CollectionView.ItemTemplate>
</CollectionView>
How can I make this work?
It seems you could not use IMarkupExtension with bindable properties .As a 'Binding' can only be set on BindableProperty of a BindableObject.The problem is that MarkupExtension class does not derive from BindableObject, that's why it is not possible to set binding on it's properties.Though you let it implement BindableObject,it still could not work.
A workaround is using Value Converters.
For example:
class ImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var p = parameter.ToString().Split('|');
string colorName = p[0];
ColorTypeConverter colorTypeConverter = new ColorTypeConverter();
Color color = (Color)colorTypeConverter.ConvertFromInvariantString(colorName);
double fontSize = double.Parse(p[1]);
//didn't test this here.
IconFontService iconFontService = SomeKindOfContainer.Resolve<IconFontService();
IconFont iconFont = iconFontService.GetIconFont();
if (iconFont == null)
return null;
string glyphCode = iconFont.GetGlyphCode((string)value);
if (string.IsNullOrEmpty(glyphCode))
return null;
FontImageSource fontImageSource = new FontImageSource()
{
FontFamily = iconFont.GetPlatformLocation(),
Glyph = glyphCode,
Color = color,
Size = fontSize,
};
return fontImageSource;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
use in your xaml:
<ContentPage.Resources>
<ResourceDictionary>
<local:ImageSourceConverter x:Key="imageConvert" />
</ResourceDictionary>
</ContentPage.Resources>
<CollectionView ItemsSource={Binding SomeCollection}">
<CollectionView.ItemTemplate>
<StackLayout>
<Image Source="{Binding Name,Converter={StaticResource imageConvert}, ConverterParameter=Color.Black|48}"/>
<Label Text="{Binding ItemText}"/>
</StackLayout>
</CollectionView.ItemTemplate>
</CollectionView>
Also see failed attempt declaring BindableProperty: IMarkupExtension with bindable property does not work and a more ambitious approach to a somewhat different situation - might be relevant: MarkupExtension for binding.
I solved this problem by creating a converter (like #Leo Zhu suggested) but in addition to the IMarkupExtension. So my extension stays as is (with the addition of a constant value that gets used in the converter) and the code for the converter is as follows:
public class FontIconConverter : IValueConverter, IMarkupExtension
{
private IServiceProvider serviceProvider;
public Color Color { get; set; }
[TypeConverter(typeof(FontSizeConverter))]
public double Size { get; set; } = FontIconExtension.DefaultFontSize;
public string FontFamily { get; set; }
public FontIconConverter()
{
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is string iconName))
return null;
var fontIcon = new FontIconExtension()
{
IconName = iconName,
Color = Color,
Size = Size,
FontFamily = FontFamily,
};
return fontIcon.ProvideValue(serviceProvider);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object ProvideValue(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
return this;
}
}
It then can be used like this:
<Image Source="{Binding IconNameProperty, Converter={c:FontIconConverter Color=Black, Size=48}}"/>
And for static values it stays like this:
<Image Source="{m:FontImage SomeIconsName, Color=Black, Size=48}"/>

Not controlled exception in WPF XAML: The specified conversion is not valid

I have a MVVM WPF application. I have below converter:
public class PrintIconVisibilityValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] == null || values[1] == null) return Visibility.Collapsed;
int item1 = (int)values[0];
string item2 = (string)values[1];
if (item1 > 0 || !string.IsNullOrEmpty(item2))
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
From my view I do:
<Window.Resources>
<classes:PrintIconVisibilityValueConverter x:Key="PrintIconVisibilityValueConverter"/>
</Window.Resources>
then I have an image in this view:
<Image Source="/MyImages;component/Images/PrintIco.png"
Height="15" Margin="20 0 5 0">
<Image.Visibility>
<MultiBinding Converter="{StaticResource PrintIconVisibilityValueConverter}">
<Binding Path="Item1" />
<Binding Path="Item2" />
</MultiBinding>
</Image.Visibility>
</Image>
Item1 and Item2 are public properties in view model:
private string _item2 = string.Empty;
public string Item2
{
get
{
return _item2;
}
set
{
if (_item2 == value) return;
_item2 = value;
OnPropertyChanged("Item2");
}
}
private int _item1;
public int Item1
{
get
{
return _item1;
}
set
{
if (_item1 == value) return;
_item1 = value;
OnPropertyChanged("Item1");
}
}
It compiles correctly and I can execute the application without problems but in design time, the view is not show, an error says Not controlled exception and points to the line:
int item1 = (int)values[0];
within PrintIconVisibilityValueConverter class.
Below the screenshots of the exception shown on view:
Some suggestions;
Call the GetIsInDesignMode method in your converter and return immediately if it returns true:
public class PrintIconVisibilityValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
return Visibility.Visible;
...
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Set the DataContext in XAML:
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
Set the design time data context:
<Window ... d:DataContext ="{d:DesignInstance {x:Type local:ViewModel}, IsDesignTimeCreatable=True}">
Or Disable XAML UI designer

WPF: Bind TabControl SelectedIndex to a View Model's Enum Property

I have a property on my ViewModel that is an enum:
ViewModel:
public MyViewModel {
// Assume this is a DependancyProperty
public AvailableTabs SelectedTab { get; set; }
// Other bound properties
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
}
public enum AvailableTabs {
Tab1,
Tab2,
Tab3
}
I'd like to be able to bind SelectedIndex (or SelectedItem) of my TabControl to this property and have it correctly set the appropriate tab using a converter. Unfortunately, I'm a bit stuck. I know I can easily just use the SelectedIndex in my model, but I want the flexibility of re-ordering the tabs without breaking anything. I've given each TabItem a Tag property of the applicable enum value.
My XAML:
<TabControl Name="MyTabControl" SelectedIndex="{Binding SelectedTab, Converter={StaticResource SomeConverter}}">
<TabItem Header="Tab 1" Tag="{x:Static local:AvailableTabs.Tab1}">
<TextBlock Text="{Binding Property1}" />
</TabItem>
<TabItem Header="Tab 2" Tag="{x:Static local:AvailableTabs.Tab2}">
<TextBlock Text="{Binding Property2}" />
</TabItem>
<TabItem Header="Tab 3" Tag="{x:Static local:AvailableTabs.Tab3}">
<TextBlock Text="{Binding Property3}" />
</TabItem>
</TabControl>
My problem is that I can't figure out how to get the TabControl into my converter so I can do:
// Set the SelectedIndex via the enum (Convert)
var selectedIndex = MyTabControl.Items.IndexOf(MyTabControl.Items.OfType<TabItem>().Single(t => (AvailableTabs) t.Tag == enumValue));
// Get the enum from the SelectedIndex (ConvertBack)
var enumValue = (AvailableTabs)((TabItem)MyTabControl.Items[selectedIndex]).Tag;
I'm afraid I might be overthinking it. I tried using a MultiValue converter without much luck. Any ideas?
You simply need a converter that casts the value to an index.
public class TabConverter : IValueConverter
{
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
return (int)value;
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
return (AvailableTabs)value;
}
}
Instead of specifying the values in the XAML, I would bind ItemsSource to an array of values from your enum:
Code:
public AvailableTabs[] AvailableTabs => Enum.GetValues(typeof(AvailableTabs Enum)).Cast<AvailableTabs>().ToArray();
XAML:
<TabControl Name="MyTabControl" SelectedIndex="{Binding SelectedTab}" ItemsSource="{Binding AvailableTabs}" />
The important thing is that the solution should work if I change the tab order in the TabControl
if this is not important then the elements in the enum type
and the views in the TabControl have to be in the same order
the conversion in this case is to cast the enum value to int value
I name the views in TabControl according to enum values
AppTab.ValidDates (enum value) corresponds to validDatesView (view name)
enum values
public enum AppTab
{
Parameters, ValidDates, ...
}
views in TabControl
<TabControl Name="myTabControl" SelectedIndex="{Binding SelectedTab, Converter={c:AppTabToIntConverter}}"
IsEnabled="{Binding IsGuiEnabled}">
<TabItem Header="{x:Static r:Resource.Parameters}">
<view:ParametersView x:Name="parametersView"/>
</TabItem>
<TabItem Header="{x:Static r:Resource.Dates}">
<view:ValidDatesView x:Name="validDatesView"/>
</TabItem>
fill up ViewNameIndexDictionary and IndexViewNameDictionary
Window_Loaded event is too late, AppTabToIntConverter runs before that
public static Dictionary<AppTab, int> ViewNameIndexDictionary { get; set; } = new Dictionary<AppTab, int>();
public static Dictionary<int, AppTab> IndexViewNameDictionary { get; set; } = new Dictionary<int, AppTab>()
private void Window_Initialized(object sender, EventArgs e)
{
var i = 0;
foreach (TabItem item in myTabControl.Items)
{
var tabContentName = ((FrameworkElement)item.Content).Name;
// Convert TabItem name "validDatesView" to "ValidDates"
var appTabString = tabContentName.FirstCharToUpper().CutLastNCharacter("View".Length);
var appTab = (AppTab)Enum.Parse(typeof(AppTab), appTabString);
ViewNameIndexDictionary.Add(appTab, i);
IndexViewNameDictionary.Add(i, appTab);
i++;
}
}
the converter
// The root tag must contain: xmlns:c="clr-namespace:LedgerCommander.ValueConverter"
class AppTabToIntConverter : BaseValueConverter<AppTabToIntConverter>
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is AppTab appTab))
throw new Exception("The type of value is not AppTab");
return MainWindowView.ViewNameIndexDictionary[appTab];
}
public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is int tabIndex))
throw new Exception("The type of value is not int");
return MainWindowView.IndexViewNameDictionary[tabIndex];
}
}
the BaseValueConverter (thanks to AngelSix)
public abstract class BaseValueConverter<T> : MarkupExtension, IValueConverter where T : class, new()
{
private static T Converter = null;
public override object ProvideValue(IServiceProvider serviceProvider)
{
return Converter ?? (Converter = new T());
}
public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}

Multi value converter does not update value

I have MultiValueConverter which show value with precision. But it seems that it does not update UI. How it is possible to solve this problem? I can not use string fromat in xaml because precision can be changed in Update(). Is it only one way to specify precision in Update() function witout converter?
Xaml:
<Window.Resources>
<design:PrecisionConverter x:Key="PrecisionConverter"/>
</Window.Resources>
<Grid>
<ToggleButton Height="30" Width="90" >
<ToggleButton.CommandParameter>
<MultiBinding Converter="{StaticResource PrecisionConverter}">
<Binding Path="Rate"/>
<Binding Path="Precision"/>
</MultiBinding>
</ToggleButton.CommandParameter>
</ToggleButton>
</Grid>
Converter:
class PrecisionConverter:IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int precision = int.Parse(values[1].ToString());
double Value = double.Parse(values[0].ToString());
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalDigits = precision;
return Value.ToString("N",nfi);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Main:
namespace WpfApplication186
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Data();
}
}
public class Data:INotifyPropertyChanged
{
private double rate;
public double Rate
{
get
{
return this.rate;
}
set
{
this.rate = value;
this.RaisePropertyChanged("Rate");
}
}
private int precision;
public int Precision
{
get
{
return this.precision;
}
set
{
this.precision = value;
this.RaisePropertyChanged("Precision");
}
}
public Data()
{
Action Test = new Action(Update);
IAsyncResult result = Test.BeginInvoke(null,null);
}
public void Update()
{
while(true)
{
System.Threading.Thread.Sleep(1000);
Rate += 0.4324232;
Precision = 2;
}
}
private void RaisePropertyChanged(string info)
{
if (PropertyChanged!=null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
You want to see the converted value?
Replace:
<ToggleButton.CommandParameter>
With
<ToggleButton.Content>
If you can't use a string formatter in XAML, you will have to create a ready-to-go property to bind to in your model.
public string BindMe
{
get { return string.Format("{0} : {1}", Rate, Precision); }
}
And in the setters for Rate and Precision, call
RaisePropertyChanged("BindMe");
Since those will imply an update to BindMe.
And in XAML do a simple bind to BindMe.
<ToggleButton.Content>
<TextBlock Text="{Binding BindMe}" />
</ToggleButton.Content>

How to using DynamicResourceExtension and IValueConverter for set color at run-time?

I have an enum :
public enum SignalColor
{
None,
Signal01A,
Signal02A
}
and LightTheme.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Colors.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!--Signal colors-->
<SolidColorBrush x:Key="Signal01ABrush" Color="#8bc34a"/>
<SolidColorBrush x:Key="Signal01BBrush" Color="#5b9914"/>
</ResourceDictionary>
I have SignalColorSelector control for choose color
<c:SignalColorSelector Name="Test" Grid.Column="0" AllowsTransparent="True" SelectedColor="Signal02A"></c:SignalColorSelector>
<c:SignalColorSelector Name="ChooseColor" Grid.Column="1" Header="Choose a color" SelectedColor="Signal01A"></c:SignalColorSelector>
How to create a class SignalColorToBrushConverter which is derived from MarkupExtension and implements IValueConverter ?
In the Convert method, the value should be of type SignalColor.
If it is SignalColor.None, return DependencyProperty.UnsetValue. Otherwise, return the corresponding signal color brush using DynamicResourceExtension.
Edit 1
I create class SignalColorToBrushConverter:
public class SignalColorToBrushConverter : MarkupExtension, IValueConverter
{
private static DynamicResourceExtension dynamicResource = new DynamicResourceExtension();
public SignalColorToBrushConverter()
{
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type tagertType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
SignalColor signalColor = (SignalColor)Enum.Parse(typeof(SignalColor), value.ToString());
switch (signalColor)
{
case SignalColor.None:
return DependencyProperty.UnsetValue;
case SignalColor.Signal01A:
dynamicResource.ResourceKey = "Signal01ABrush";
break;
case SignalColor.Signal01B:
dynamicResource.ResourceKey = "Signal01BBrush";
break;
case SignalColor.Signal02A:
dynamicResource.ResourceKey = "Signal02ABrush";
break;
case SignalColor.Signal02B:
dynamicResource.ResourceKey = "Signal02BBrush";
break;
}
try
{
return Application.Current.FindResource(dynamicResource.ResourceKey);
}
catch (ResourceReferenceKeyNotFoundException)
{
return DependencyProperty.UnsetValue;
}
}
then, using it:
<TextBlock Text="Choose a color" Width="100" FontWeight="Bold" HorizontalAlignment="Left"
Foreground="{Binding Path=SelectedColor, Converter={v:SignalColorToBrushConverter}, ElementName=ChooseColor}"/>
You can create a Markup Extension like below
public class SignalColorExtension : MarkupExtension
{
public SignalColor IncomingSignalColor
{
get;
set;
}
public SignalColorExtension() { }
public SignalColorExtension(string color)
{
SignalColor outColor;
if (! SignalColor.TryParse(color,true,out outColor))
IncomingSignalColor = SignalColor.None;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
var host = target.TargetObject as FrameworkElement;
if (host != null && IncomingSignalColor != SignalColor.None)
{
var colorResourse = host.TryFindResource(IncomingSignalColor.ToString());
return colorResourse;
}
return DependencyProperty.UnsetValue;
}
}
and use find Resource on the TargetObject to find the colors if they exist just like dynamicresource markup. And then you can use your markup like below:
<Grid Background="{sigColor:SignalColor Signal01A}" >
where sigColor is my namespace to the assembly where my markup extension exists.

Categories