ResourceComparisonConverter - lucyberryhub/WPF.Tutorial GitHub Wiki

๐Ÿ’DynamicResource in Style.Triggers๐Ÿ“โœจ

๐ŸŒŸ 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!


1๏ธโƒฃ What's the Berry-Problem?

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! ๐Ÿ“โœจ


2๏ธโƒฃ Berry-Solution Overview!

Weโ€™ll:

  1. Create a custom ResourceComparisonConverter.
  2. Use it in a Style.Trigger.
  3. Dynamically set resources in the code-behind.

3๏ธโƒฃ The Full Berry-Sweet XAML

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>

4๏ธโƒฃ The Berry-Converter

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();
        }
    }
}

5๏ธโƒฃ Set the Dynamic Resource in Code-Behind

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";
    }
}

6๏ธโƒฃ Lucyโ€™s Berry Breakdown!

  • ๐Ÿ“ Dynamic Resource Trickery: Use a converter to fetch the resource value from the Resources dictionary.
  • ๐Ÿ’ Trigger Magic: Compare the bound ComboValue with the specialBindingProperty.
  • ๐ŸŒธ Code-Behind Connection: Dynamically change specialBindingProperty as needed.

7๏ธโƒฃ Test Your Berry-Creation!

When you bind ComboValue to "BerrySpecialValue", the TextBlock turns transparent with a cute tooltip! ๐Ÿ’โœจ


๐Ÿ’ Berry, Cherry, and Juicy Localizations ๐Ÿ“

๐Ÿ’ก Overview

Next Lucy wants to work with a DataGrid that supports:

  1. Multiple juicy berry values (e.g., cherry_round, blueberry_square, strawberry_triangle).
  2. Comparing selected combo berry values (comboBerryValue) against localized fruity strings.
  3. Resetting invalid entries with a juicy warning message if the user selects the forbidden fruit! ๐Ÿ“

๐Ÿ“ Step 1: Updating the TemplateHelper

Lucyโ€™s TemplateHelper is now updated to handle a list of berry localizations, like cherry_round, blueberry_square, and strawberry_star.

Code

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;
}

๐Ÿ’ Step 2: Shared KeyUp Event Handler

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! ๐Ÿ“

Code

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;
                }
            }
        }
    }
}

๐Ÿ“ Step 3: Localized Berry DataGrid Setup

Lucyโ€™s DataGrid columns now use a list of berry values like:

  • cherry_round
  • blueberry_square
  • strawberry_star
  • raspberry_diamond
  • blackberry_hexagon

Code

BerryCellEditingTemplate = TemplateHelper.CreateBerryEditingTemplate("BerryDimensionText",
    new List<string>
    {
        localizedBerries["cherry_round"],
        localizedBerries["blueberry_square"],
        localizedBerries["strawberry_star"]
    });

๐Ÿ’ Step 4: Adding Columns

Lucyโ€™s fruity DataGrid looks as juicy as ever! ๐Ÿ“ She defines a variety of berry-related columns for her app.

Code

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);

๐Ÿ“ Lucyโ€™s Juicy Takeaways

  1. Reusable Templates: By using lists of localized berries, Lucy can easily update or add new fruits to her DataGrid.
  2. Error Handling: Invalid entries are reset, and the user receives a friendly fruity warning.
  3. Juicy UX: The fruity column headers and warnings make the app fun and interactive! ๐Ÿ’

โš ๏ธ **GitHub.com Fallback** โš ๏ธ