ResourceComparisonConverter - lucyberryhub/WPF.Tutorial GitHub Wiki
๐ Hello my sweet berries! ๐ Today, Lucy will teach you how to work around the DynamicResource in Style.Triggers problem with berry-level cuteness and clarity. ๐โจ Let's make it work using a custom converter (BerryResourceComparisonConverter
) and dynamic resources!
Normally, you can't directly use a DynamicResource
in a Style.Trigger
. This gives a big "no-no" error! ๐จ Donโt worry; Lucy's here to save the day with her magic converter! ๐โจ
Weโll:
- Create a custom
ResourceComparisonConverter
. - Use it in a
Style.Trigger
. - Dynamically set resources in the code-behind.
Hereโs your juicy CuteTableView
control, all dressed up:
<UserControl x:Class="CherryBerry.Templates.CuteTableView"
x:Name="BerryControl" <!-- ๐ Important for referencing in code -->
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:berry="clr-namespace:CherryBerry.DynamicMenuItem.ViewModels" <!-- ๐ Your berry-sweet namespace -->
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<!-- ๐ Define a placeholder for the special property -->
<sys:String x:Key="specialBindingProperty">DefaultBerry</sys:String>
<!-- ๐ Add a dynamic foreground brush -->
<SolidColorBrush x:Key="cor_brush_ThemeForeground" Color="BerryBlue"/>
<!-- ๐ธ Include our berry-licious converter -->
<berry:BerryResourceComparisonConverter x:Key="BerryResourceComparisonConverter"/>
</UserControl.Resources>
<Grid>
<!-- ๐ TextBlock Style -->
<Style x:Key="foregroundTextStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource cor_brush_ThemeForeground}"/> <!-- ๐ธ Default berry dynamic color -->
<Style.Triggers>
<DataTrigger Binding="{Binding ComboValue,
Converter={StaticResource BerryResourceComparisonConverter},
ConverterParameter={x:Reference BerryControl}}"
Value="True">
<Setter Property="Foreground" Value="Transparent"/> <!-- ๐ Hide berry text if matched -->
<Setter Property="ToolTip" Value="This berry text is read-only."/>
</DataTrigger>
</Style.Triggers>
</Style>
<!-- ๐ Sweet TextBlock -->
<TextBlock Text="Hello, cherries and berries!" Style="{StaticResource foregroundTextStyle}"/>
</Grid>
</UserControl>
Create the BerryResourceComparisonConverter
in your code:
using System;
using System.Globalization;
using System.Windows.Data;
namespace CherryBerry.DynamicMenuItem.ViewModels
{
public class BerryResourceComparisonConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter is FrameworkElement frameworkElement)
{
// ๐ Get the resource value dynamically
string resourceValue = frameworkElement.Resources["specialBindingProperty"] as string;
return resourceValue != null && resourceValue.Equals(value?.ToString(), StringComparison.OrdinalIgnoreCase);
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Set your resource dynamically in the code-behind like this:
public partial class CuteTableView : UserControl
{
public CuteTableView()
{
InitializeComponent();
// ๐ Dynamically set the special property
this.Resources["specialBindingProperty"] = "BerrySpecialValue";
}
}
- ๐ Dynamic Resource Trickery: Use a converter to fetch the resource value from the
Resources
dictionary. - ๐ Trigger Magic: Compare the bound
ComboValue
with thespecialBindingProperty
. - ๐ธ Code-Behind Connection: Dynamically change
specialBindingProperty
as needed.
When you bind ComboValue
to "BerrySpecialValue"
, the TextBlock
turns transparent with a cute tooltip! ๐โจ
Next Lucy wants to work with a DataGrid that supports:
- Multiple juicy berry values (e.g.,
cherry_round
,blueberry_square
,strawberry_triangle
). - Comparing selected combo berry values (
comboBerryValue
) against localized fruity strings. - Resetting invalid entries with a juicy warning message if the user selects the forbidden fruit! ๐
Lucyโs TemplateHelper
is now updated to handle a list of berry localizations, like cherry_round
, blueberry_square
, and strawberry_star
.
public static DataTemplate CreateBerryEditingTemplate(string berryBindingProperty, List<string> berryLocalizedStrings = null)
{
var berryTemplate = new DataTemplate(typeof(TextBox));
var berryTextBoxFactory = new FrameworkElementFactory(typeof(TextBox));
berryTextBoxFactory.SetBinding(TextBox.TextProperty, new Binding(berryBindingProperty) { Mode = BindingMode.TwoWay });
berryTextBoxFactory.SetValue(TextBox.VerticalContentAlignmentProperty, VerticalAlignment.Center);
berryTextBoxFactory.SetValue(TextBox.HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
if (berryLocalizedStrings != null && berryLocalizedStrings.Any())
{
berryTextBoxFactory.SetValue(FrameworkElement.TagProperty, berryLocalizedStrings);
berryTextBoxFactory.AddHandler(TextBox.KeyUpEvent, new System.Windows.Input.KeyEventHandler(SharedBerryTextBox_KeyUp));
}
berryTemplate.VisualTree = berryTextBoxFactory;
return berryTemplate;
}
The SharedBerryTextBox_KeyUp
method now checks the fruity values passed in the Tag
property against the current comboBerryValue. If a match is found, reset the TextBox to "0"
and show a warning about forbidden fruit! ๐
private static void SharedBerryTextBox_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
if (sender is TextBox berryTextBox && berryTextBox.IsFocused)
{
var berryLocalizedStrings = berryTextBox.Tag as List<string>;
if (berryLocalizedStrings != null)
{
foreach (var berryString in berryLocalizedStrings)
{
if (berryString == comboBerryValue)
{
berryTextBox.Text = "0"; // Reset the berry value
MessageBox.Show($"{berryString} is not allowed here! ๐", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
break;
}
}
}
}
}
Lucyโs DataGrid
columns now use a list of berry values like:
cherry_round
blueberry_square
strawberry_star
raspberry_diamond
blackberry_hexagon
BerryCellEditingTemplate = TemplateHelper.CreateBerryEditingTemplate("BerryDimensionText",
new List<string>
{
localizedBerries["cherry_round"],
localizedBerries["blueberry_square"],
localizedBerries["strawberry_star"]
});
Lucyโs fruity DataGrid looks as juicy as ever! ๐ She defines a variety of berry-related columns for her app.
var berryColumns = new List<DataGridColumn>
{
new DataGridTextColumn
{
Header = localizedBerries["berry_name"],
Binding = new Binding("BerryName") { Mode = BindingMode.TwoWay },
Width = new DataGridLength(1, DataGridLengthUnitType.Star)
},
new DataGridComboBoxColumn
{
Header = localizedBerries["berry_shape"],
ItemsSource = new List<string>
{
localizedBerries["cherry_round"],
localizedBerries["blueberry_square"],
localizedBerries["strawberry_star"],
localizedBerries["raspberry_diamond"],
localizedBerries["blackberry_hexagon"]
},
SelectedItemBinding = new Binding("BerryShape") { Mode = BindingMode.TwoWay },
Width = new DataGridLength(1, DataGridLengthUnitType.Star)
},
new DataGridTemplateColumn
{
Header = localizedBerries["berry_size"],
CellEditingTemplate = TemplateHelper.CreateBerryEditingTemplate("BerrySizeText",
new List<string>
{
localizedBerries["cherry_round"],
localizedBerries["blueberry_square"]
}),
Width = new DataGridLength(1, DataGridLengthUnitType.Star)
}
};
BerryTableControl.SetBerryColumns(berryColumns);
- Reusable Templates: By using lists of localized berries, Lucy can easily update or add new fruits to her DataGrid.
- Error Handling: Invalid entries are reset, and the user receives a friendly fruity warning.
- Juicy UX: The fruity column headers and warnings make the app fun and interactive! ๐