Tuỳ thuộc và Thuộc tính Gắn thêm

1. Thuộc tính Tuỳ thuộc

Thuộc tính tuỳ thuộc là một loại thuộc tính có thể không có giá trị riêng và có thể nhận giá trị từ nguồn dữ liệu thông qua Binding.

Lớp DependencyObject trong WPF thực hiện khái niệm đối tượng tuỳ thuộc, còn lớp DependencyProperty thực hiện khái niệm thuộc tính tuỳ thuộc. Lớp DependencyObject có các phương thức GetValue và SetValue.

Dưới đây là cách tạo thuộc tính tuỳ thuộc IsHighlighted:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        // Khai báo thuộc tính công khai
        CustomTextBox customTextBox = new CustomTextBox();
        customTextBox.IsHighlighted = true;
        // Hoặc sử dụng SetValue trực tiếp
        customTextBox.SetValue(CustomTextBox.IsHighlightedProperty, true);
    }
}

public class CustomTextBox : TextBox
{
    public bool IsHighlighted
    {
        get { return (bool)GetValue(IsHighlightedProperty); }
        set { SetValue(IsHighlightedProperty, value); }
    }

    public static readonly DependencyProperty IsHighlightedProperty =
        DependencyProperty.Register("IsHighlighted", typeof(bool), typeof(CustomTextBox), new PropertyMetadata(false));

    #region HasText - Thuộc tính tuỳ thuộc chỉ đọc
    public bool HasText => (bool)GetValue(HasTextProperty);

    public static readonly DependencyProperty HasTextProperty;
    public static readonly DependencyPropertyKey HasTextPropertyKey;

    static CustomTextBox()
    {
        HasTextPropertyKey = DependencyProperty.RegisterReadOnly(
            "HasText",
            typeof(bool),
            typeof(CustomTextBox),
            new PropertyMetadata(false)
        );
        HasTextProperty = HasTextPropertyKey.DependencyProperty;
    }
    #endregion
}
<Window x:Class="Test_05.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:Test_05"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>
        <Style TargetType="local:CustomTextBox">
            <Style.Triggers>
                <Trigger Property="IsHighlighted" Value="True">
                    <Setter Property="Background" Value="Yellow"></Setter>
                </Trigger>
                <Trigger Property="IsHighlighted" Value="False">
                    <Setter Property="Background" Value="Blue"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <local:CustomTextBox Text="Hello World!" FontSize="30" IsHighlighted="True"></local:CustomTextBox>
    </StackPanel>
</Window>

2. Thuộc tính Gắn thêm

Thuộc tính gắn thêm cho phép đặt các cặp thuộc tính/giá trị bổ sung cho bất kỳ phần tử XAML nào được phái sinh từ DependencyObject, ngay cả khi phần tử đó không định nghĩa các thuộc tính bổ sung trong mô hình đối tượng của nó.

Dưới đây là cách tạo các thuộc tính gắn thêm HasText và MonitorTextChange để liên kết trạng thái chọn của CheckBox với việc TextBox có rỗng hay không:

<Window x:Class="Test_01.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:Test_01"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <TextBox x:Name="tBox" Text="1234" FontSize="30" local:TextBoxHelper.MonitorTextChange="True"></TextBox>
        <CheckBox IsChecked="{Binding ElementName=tBox, Path=(local:TextBoxHelper.HasText)}" FontSize="30"></CheckBox>
    </StackPanel>
</Window>
public class TextBoxHelper
{
    public static bool GetHasText(DependencyObject obj)
    {
        return (bool)obj.GetValue(HasTextProperty);
    }

    public static void SetHasText(DependencyObject obj, bool value)
    {
        obj.SetValue(HasTextProperty, value);
    }

    public static readonly DependencyProperty HasTextProperty =
        DependencyProperty.RegisterAttached(
            "HasText",
            typeof(bool),
            typeof(TextBoxHelper),
            new PropertyMetadata(false)
        );

    public static bool GetMonitorTextChange(DependencyObject obj)
    {
        return (bool)obj.GetValue(MonitorTextChangeProperty);
    }

    public static void SetMonitorTextChange(DependencyObject obj, bool value)
    {
        obj.SetValue(MonitorTextChangeProperty, value);
    }

    public static readonly DependencyProperty MonitorTextChangeProperty =
        DependencyProperty.RegisterAttached(
            "MonitorTextChange",
            typeof(bool),
            typeof(TextBoxHelper),
            new PropertyMetadata(false, OnMonitorTextChangedPropertyChanged)
        );

    private static void OnMonitorTextChangedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not TextBox box)
        {
            throw new NotSupportedException();
        }
        if ((bool)e.NewValue)
        {
            box.TextChanged += OnTextChanged;
            SetHasText(box, !string.IsNullOrEmpty(box.Text));
        }
        else
        {
            box.TextChanged -= OnTextChanged;
        }
    }

    private static void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var box = (TextBox)sender;
        SetHasText(box, !string.IsNullOrEmpty(box.Text));
    }
}

Thẻ: DependencyProperty DependencyObject WPF XAML AttachedProperties

Đăng vào ngày 1 tháng 7 lúc 02:08