Hello,
i had a custom user control which i use in a GridView Column. The foreground should change by a binded value and a IValueConverter. The "Bad" state is red and the normal state is the default theme color.
The result should look like this (But it does only with a dirty hack -> use 2 idendical textblock and hide one or the other):
BUT i dont know how to get the default foreground (yellow unselected and white selected)
I tried:
- return null in the IValueConverter -> No Color/Brush at all
- Use a Multibinding and return the given second Binding: <Binding Source="{x:Static telerik:CrystalPalette.Palette}" Path="MarkerColor"/> -> Select state is not respected
- Use a Multibinding to a "Helper" Element and return the value <Binding ElementName="ColorHelper" Path="Foreground"/>
<TextBlock Name="ColorHelper" Foreground="{telerik:CrystalResource ResourceKey={x:Static telerik:CrystalResourceKey.MarkerBrush}}"> </TextBlock> -> Select state is not respected
1 Answer, 1 is accepted
Hello Marco,
Thank you for the shared picture.
My current understanding is that you have modified the MarkeColor of the Crystal theme to Orange and you would like to change the Foreground inside the cells of a specific column depending on a condition, but otherwise leave the default/selected Foreground colors. Feel free to correct me, if I am wrong and elaborate on the scenario.
I am attaching a sample project to demonstrate a possible way to achieve the desired result. It involves creating a Style targeting GridViewCell and conditionally setting the Foreground inside a DataTrigger. This will take precedence over the default colors.
Can you check out the shared sample project and let me know, if it helps?
Regards,
Vladimir Stoyanov
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Thank you very much! This solved my problem(s).
Is there a way for doing this with a ValueConverter for more complex use cases? I thought of something like "return null" for the default color, but it doesn't work.
regards
Marco
I am glad to hear that you found the sample project helpful. While I am uncertain of the exact scenario, you can also use an IValueConverter and a binding for the value of the Foreground. I am attaching back the sample project modified to demonstrate this approach.
If that is not what you had in mind, can you elaborate on your scenario? If you find it possible, you can update the sample project in order to demonstrate the idea and send it back.
Hello Vladimir,
thank you again for your efforts! Your second example does not match my scenario.
concrete example:
The user can define a custom color-table on which value which color should be used as fore- or background.
I need something like this (very simplified and adapted to your example):
public class Converter : IValueConverter
{
Dictionary<int, Brush> colorDict = new Dictionary<int, Brush>()
{
{1880, new SolidColorBrush(Colors.BlueViolet)},
{1890, new SolidColorBrush(Colors.Aquamarine)},
{1900, new SolidColorBrush(Colors.Fuchsia)}
};
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is DateTime est)
{
var color = colorDict.OrderBy(x => x.Key).FirstOrDefault(x => x.Key > est.Year);
if (!color.Equals(default(KeyValuePair<int, Brush>)))
return color.Value;
}
return default; // <- ??? how do i get the default foreground color?
return null; // <- doesnt work
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I dont think I can build this or even more complex requirements up as xaml trigger.
regards marco
In the demonstrated scenario, you can return a SolidColorBrush with the color from the palette that is used in the scenario. Here is some sample code:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is DateTime est)
{
var color = colorDict.OrderBy(x => x.Key).FirstOrDefault(x => x.Key > est.Year);
if (!color.Equals(default(KeyValuePair<int, Brush>)))
return color.Value;
}
return new SolidColorBrush(CrystalPalette.Palette.MarkerColor);
//return null; // <- doesnt work
}
I hope you find this helpful.
Hello,
and again, thank you for your efforts. The Problem is, that the user can chose their Theme freely or set the app in DarkMode, even special Themes for some controls. With your solution i had to consider this every time for every converter with every theme/mode/variation.
For now i helped me out with a hybrid approach:
I build a bool variable which breaks the complex calculation down to true or false. Than i use a trigger like you given in your example.
In my simplified example it will look something like this:
ViewModel (pseudo code):
public bool IsInRange { get { return Value > colorDict.Min() && Value < colorDict.Max(); } }
The Converter stays mainly the same, but the default-case should never be occur and its now an MultiConverter to transfer indiviual colorDictionaries:
internal class ColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is double value && values[1] is ColorDict colorDict)
{
foreach (var color in colorDict)
{
if (value > color.Value)
return new SolidColorBrush(color.BackgroundColor);
}
}
// Should never occur
return new SolidColorBrush(Colors.DeepPink);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The Xaml Trigger:
<Style x:Key="ColorColumnStyle" TargetType="telerik:GridViewCell" >
<Style.Triggers>
<DataTrigger Binding="{Binding IsInRange}" Value="True">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource ColorConverter}">
<Binding Path="Value" />
<Binding Path="colorDict"/>
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
I am glad to hear that you have achieved what you were going for. Indeed creating a custom property and using a MultiBinding is a nice approach.
Thank you for sharing your implementation.
So finally i came up with a nearly "perfect" solution.
I define per theme the marker color and return it in the value converters.
When the theme changes:
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = new Uri($@"/MyApplication;component/Styles/{themeName}Styles.xaml", UriKind.RelativeOrAbsolute)
});
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:actions="clr-namespace:Infrastructure.Actions;assembly=Infrastructure">
<SolidColorBrush x:Key="BasicColorBrush" Color="{Binding Source={x:Static telerik:Windows8Palette.Palette}, Path=BasicColor}"/>
<SolidColorBrush x:Key="MainColorBrush" Color="{Binding Source={x:Static telerik:Windows8Palette.Palette}, Path=MainColor}"/>
<SolidColorBrush x:Key="MarkerColorBrush" Color="{Binding Source={x:Static telerik:Windows8Palette.Palette}, Path=MarkerColor}"/>
</ResourceDictionary>
And finally in the ValueConverter i can use:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is DateTime est)
{
var color = colorDict.OrderBy(x => x.Key).FirstOrDefault(x => x.Key > est.Year);
if (!color.Equals(default(KeyValuePair<int, Brush>)))
return color.Value;
}
return Application.Current.TryFindResource("MarkerColorBrush");
}