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}"/>
Related
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);
}
Am having a scenario , where i have a BaseImageUrl String
private const string BaseImageUrl = "http://eamobiledirectory.com/cooperp/Images/app_images/";
for the images i want to retrieve into the Image view in Xaml plus concatenating it with a string value office_photo which has the exact image name forexample flower.jpg and is got after deserializing JSON and it comes as a List , below is my Model class :
public class Adverts
{
public string office_photo { get; set; }
public DateTime entryDate { get; set; }
}
so what i want is how to concatenate the BaseUrl and office_photo in XAML so that i get the complete link to images .
below is my Image in the ListView :
<ListView x:Name="listViewTest" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image Aspect="AspectFill" Source="{Binding office_photo}" x:Name="advertImage"
WidthRequest="200"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Just concatenate the two strings in a new property in your view modem and bind to that property. It's really simple and one line of code :-)
Something like this:
public string PhotoUrl { get { return BaseImageUrl + office_photo; }}
Use a IValueConverter
Something like
public class AddBaseUrlConverter : IValueConverter
{
#region IValueConverter implementation
private const string BaseImageUrl = "http://eamobiledirectory.com/cooperp/Images/app_images/";
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && ! string.IsNullOrEmpty((string)value)) {
return string.Format("{0}{1}", BaseImageUrl, (string)value);
}
return ""; //
}
public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException ();
}
#endregion
}
Then in your XAML something like
<ContentPage.Resources>
<ResourceDictionary>
< AddBaseUrlConverter x:Key="cnvInvert"></AddBaseUrlConverter >
</ResourceDictionary>
</ContentPage.Resources>
<Image Aspect="AspectFill" Source="{Binding office_photo, Converter={StaticResource cnvInvert}}" x:Name="advertImage" WidthRequest="200"/>
(not tested, but it could work)
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:
I am new to WPF and here I am trying to set a simple string property of my viewModel when a particular radio button is checked on my window.
class ViewModel
{
string LanguageSettings {get;set;}
}
XAML looks like following:
<RadioButton Name="OptionEnglish" GroupName="LanguageOptions" IsChecked="{Binding LanguageSettings, Converter={StaticResource Converter}, ConverterParameter=English}" Content="English" HorizontalAlignment="Right" Width="760" />
<RadioButton Name="OptionChinese" GroupName="LanguageOptions" IsChecked="{Binding LanguageSettings, Converter={StaticResource Converter}, ConverterParameter=Chinese}" Content="Chinese" />
I have implemented the IValueConverted which looks like below:
public class BoolInverterConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
#endregion
}
Probably I am not properly understanding the utility of IValueConverter. I think if I change it appropriately it might work.
All I want here is that when English is selected I want Language Settings to be set as English and same for Chinese. Is there any simple way to do it? is there any straightforward way to set that property?
So i do have two options
1.Change my BoolConverterImplementation
2. Find another easier way to do it.
Any ideas?
An approach that does not require a converter:
<RadioButton Content="Chinese" IsChecked="{Binding IsChinese}"/>
<RadioButton Content="English" IsChecked="{Binding IsEnglish}"/>
ViewModel:
public class LanguageSelectorViewModel
{
private bool _isChinese;
private bool _isEnglish;
public bool IsChinese
{
get { return _isChinese; }
set
{
_isChinese = value;
if (value)
SelectedLanguage = "Chinese";
}
}
public bool IsEnglish
{
get { return _isEnglish; }
set
{
_isEnglish = value;
if (value)
SelectedLanguage = "English";
}
}
public string SelectedLanguage { get; set; }
}
You should look into implementing IValueConverter. Below is a starting example for what I believe you are looking for:
public class StringMatchConverter : IValueConverter
{
public object Convert(object value,Type targetType,object parameter,CultureInfo culture)
{
return value == parameter;
}
public object ConvertBack(object value,Type targetType,object parameter,CultureInfo culture)
{
throw new NotImplementedException();
}
}
Example usage:
<!-- Somewhere in resources -->
<conv:StringMatchConverter x:Key="Conv" />
<!-- Somewhere in application -->
<RadioButton Name="OptionEnglish" GroupName="LanguageOptions" IsChecked="{Binding LanguageSettings,Converter={StaticResource Conv}, ConverterParameter=English}" Content="English" HorizontalAlignment="Right" Width="760" />
<RadioButton Name="OptionChinese" GroupName="LanguageOptions" IsChecked="{Binding LanguageSettings,Converter={StaticResource Conv}, ConverterParameter=Chinese}" Content="Chinese" />
I'm not sure but if I understand you correct you maybe could use a IValueConverter.
One way to do it would be to create an attached property:
public class MyAttachedProperty
{
public static readonly DependencyProperty IsCheckedToStrProperty =
DependencyProperty.RegisterAttached("IsCheckedToStr", typeof (string), typeof (MyAttachedProperty), new PropertyMetadata(default(string,IsCheckedToStr)))
private static void IsCheckedToStr(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RadioButton radio = d as RadioButton;
radio.Checked+=radio_Checked;
}
private static void radio_Checked(object sender, RoutedEventArgs e)
{
RadioButton radio = sender as RadioButton;
if (radio.IsChecked == true)
{
SetIsCheckedToStr(radio, radio.Content.ToString());
}
}
public static void SetIsCheckedToStr(UIElement element, string value)
{
element.SetValue(IsCheckedToStrProperty, value);
}
public static string GetIsCheckedToStr(UIElement element)
{
return (string) element.GetValue(IsCheckedToStrProperty);
}
}
And then you can use it in your xaml like this:
<RadioButton Name="OptionEnglish" GroupName="LanguageOptions" local:MyAttachedProperty.IsCheckedStr="{Binding LanguageSettings}" Content="English" HorizontalAlignment="Right" Width="760" />
<RadioButton Name="OptionChinese" GroupName="LanguageOptions" local:MyAttachedProperty.IsCheckedStr="{Binding LanguageSettings}" Content="Chinese" />
I have the exact name of a brush (AliceBlue, OrangeRed, etc) and I wonder if it is possible to select the brush by this string. Brushes is a static collection and I don't really know how to do this. I think in a normal collection it could be done by selecting the name property of an item with Linq, but doesn't seem to work here.
Use BrushConverter from the System.ComponentModel namespace:
BrushConverter conv = new BrushConverter();
You can use a color name:
SolidColorBrush brush = conv.ConvertFromString("Red") as SolidColorBrush;
You can also use an RGB value:
SolidColorBrush brush = conv.ConvertFromString("#0000FF") as SolidColorBrush;
You could do it with reflection easily enough:
// TODO: Validation :)
Brush brush = (Brush) typeof(Brushes).GetProperty(name)
.GetValue(null);
Alternatively, you could use reflection once to populate a dictionary:
Dictionary<string, Brush> =
typeof(Brushes).GetProperties(BindingFlags.Public |
BindingFlags.Static)
.ToDictionary(p => p.Name,
p => (Brush) p.GetValue(null));
From BrushConverter class (MSDN):
Use this class to convert a string into a SolidColorBrush or an
ImageBrush. See these type pages for syntax information. This class is
typically used by the parser to convert attribute strings to brushes.
SolidColorBrush redBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("Red");
You can create your own StringToBrushConverter and use above code in its Convert method by passing your string color variables and returning SolidColorBrush variables.
I have two solution for you.
one use A SolidColorBrush property and set it with your desire property like below.
And other one is use convert with BrushConverter Class.
<Window x:Class="WpfApplication1.DynamicSorting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DynamicSorting" Height="329" Width="610">
<Window.Resources>
<local:StringToBrushConverter x:Key="texttobrush"/>
</Window.Resources>
<Grid Background="{Binding SelectedBrush,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="242*" />
<ColumnDefinition Width="346*" />
</Grid.ColumnDefinitions>
<ComboBox Height="35" SelectedItem="{Binding SelectedBrush,Mode=TwoWay}" ItemsSource="{Binding AllBrushes}" HorizontalAlignment="Left" Margin="25,32,0,0" x:Name="comboBox1" VerticalAlignment="Top" Width="143" />
</Grid>
</Window>
public partial class DynamicSorting : Window, INotifyPropertyChanged
{
public DynamicSorting()
{
InitializeComponent();
if (FilesList == null)
FilesList = new ObservableCollection<FileInfo>();
var files = new System.IO.DirectoryInfo("C:\\Windows\\System32\\").GetFiles();
foreach (var item in files)
{
FilesList.Add(item);
}
if (AllBrushes == null)
AllBrushes = new ObservableCollection<string>();
Type t = typeof(Brushes);
var props = t.GetProperties();
foreach (var item in props)
{
AllBrushes.Add(item.Name);
}
this.DataContext = this;
}
private SolidColorBrush _SelectedBrush;
public SolidColorBrush SelectedBrush
{
get { return _SelectedBrush; }
set
{
_SelectedBrush = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("SelectedBrush"));
}
}
public ObservableCollection<FileInfo> FilesList { get; set; }
public ObservableCollection<string> AllBrushes { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
public class StringToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return Brushes.Transparent;
var colortext = value.ToString();
var BrushType = typeof(Brushes);
var brush = BrushType.GetProperty(colortext);
if (brush != null)
return brush;
return Brushes.Transparent;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}