完全来源于十月的寒流,感谢大佬讲解
依赖属性
由依赖属性提供的属性功能
与字段支持的属性不同,依赖属性扩展了属性的功能。 通常,添加的功能表示或支持以下功能之一:
- 资源
- 数据绑定
- 样式
- 动画
- 元数据重写
- 属性值继承
- WPF 设计器集成
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CustomTextBox customTextBox = new CustomTextBox();
customTextBox.IsHightLighted = true;
customTextBox.SetValue(CustomTextBox.IsHightLightedProperty, true);
}
}
public class CustomTextBox : TextBox
{
public bool IsHightLighted
{
get { return (bool)GetValue(IsHightLightedProperty); }
set { SetValue(IsHightLightedProperty, value); }
}
public static readonly DependencyProperty IsHightLightedProperty =
DependencyProperty.Register("IsHightLighted", typeof(bool), typeof(CustomTextBox), new PropertyMetadata(false));
}
#region HasText
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="IsHightLighted" Value="True">
<Setter Property="Background" Value="Yellow"></Setter>
</Trigger>
<Trigger Property="IsHightLighted" Value="False">
<Setter Property="Background" Value="Blue"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<local:CustomTextBox Text="Hello World!" FontSize="30" IsHightLighted="True"></local:CustomTextBox>
</StackPanel>
</Window>
附加属性
<StackPanel>
<!--<local:CustomTextBox Text="Hello World!" FontSize="30" IsHightLighted="True"></local:CustomTextBox>-->
<local:CustomTextBox Text="Hello World!" FontSize="30">
<local:CustomTextBox.IsHightLighted>
true
</local:CustomTextBox.IsHightLighted>
<Grid.Row>1</Grid.Row>
</local:CustomTextBox>
</StackPanel>
<StackPanel>
<local:CustomTextBox x:Name="aoteman" local:TextBoxHelper.Title="this is test" FontSize="30"
Text="{Binding RelativeSource={RelativeSource self}, Path=(local:TextBoxHelper.Title)}"></local:CustomTextBox>
<!--<local:CustomTextBox x:Name="aoteman" FontSize="30"
Text="{Binding RelativeSource={RelativeSource self}, Path=(local:TextBoxHelper.Title)}"></local:CustomTextBox>-->
</StackPanel>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//TextBoxHelper.SetTitle(aoteman, "this is aoteman");
}
}
public class CustomTextBox : TextBox
{
public bool IsHightLighted
{
get { return (bool)GetValue(IsHightLightedProperty); }
set { SetValue(IsHightLightedProperty, value); }
}
public static readonly DependencyProperty IsHightLightedProperty =
DependencyProperty.Register("IsHightLighted", typeof(bool), typeof(CustomTextBox), new PropertyMetadata(false));
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;
}
}
public class TextBoxHelper
{
public static string GetTitle(DependencyObject obj)
{
return (string)obj.GetValue(TitleProperty);
}
public static void SetTitle(DependencyObject obj, string value)
{
obj.SetValue(TitleProperty, value);
}
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleProperty =
DependencyProperty.RegisterAttached("Title", typeof(string), typeof(TextBoxHelper), new PropertyMetadata(""));
}
TextBox HasText实现一
<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">
<Window.Resources>
</Window.Resources>
<StackPanel>
<!--<local:CustomTextBox x:Name="aoteman" local:TextBoxHelper.Title="this is test" FontSize="30"
Text="{Binding RelativeSource={RelativeSource self}, Path=(local:TextBoxHelper.Title)}"></local:CustomTextBox>-->
<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>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Test_01
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
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);
}
// Using a DependencyProperty as the backing store for MonitorTextChange. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MonitorTextChangeProperty =
DependencyProperty.RegisterAttached(
"MonitorTextChange",
typeof(bool),
typeof(TextBoxHelper),
new PropertyMetadata(false, MonitorTextChangedPropertyChanged)
);
private static void MonitorTextChangedPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e
)
{
if (d is TextBox box == false)
{
throw new NotSupportedException();
}
if ((bool)e.NewValue)
{
box.TextChanged += TextChanged;
SetHasText(box, !string.IsNullOrEmpty(box.Text));
}
else
{
box.TextChanged -= TextChanged;
}
}
private static void TextChanged(object sender, TextChangedEventArgs e)
{
var box = sender as TextBox;
SetHasText(box, !string.IsNullOrEmpty(box.Text));
}
}
}
TextBox HasText只读实现二
<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">
<Window.Resources>
</Window.Resources>
<StackPanel>
<!--<local:CustomTextBox x:Name="aoteman" local:TextBoxHelper.Title="this is test" FontSize="30"
Text="{Binding RelativeSource={RelativeSource self}, Path=(local:TextBoxHelper.Title)}"></local:CustomTextBox>-->
<TextBox x:Name="tBox" Text="1234" FontSize="30" local:TextBoxHelper.MonitorTextChange="True"></TextBox>
<CheckBox IsChecked="{Binding ElementName=tBox, Path=(local:TextBoxHelper.HasText), Mode=OneWay}" FontSize="30"></CheckBox>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Test_01
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class TextBoxHelper
{
static TextBoxHelper()
{
HasTextProperty = HasTextPropertyKey.DependencyProperty;
}
public static bool GetHasText(DependencyObject obj)
{
return (bool)obj.GetValue(HasTextProperty);
}
public static void SetHasText(DependencyObject obj, bool value)
{
obj.SetValue(HasTextPropertyKey, value);
}
public static readonly DependencyProperty HasTextProperty;
public static readonly DependencyPropertyKey HasTextPropertyKey =
DependencyProperty.RegisterAttachedReadOnly(
"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, MonitorTextChangedPropertyChanged)
);
private static void MonitorTextChangedPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e
)
{
if (d is TextBox box == false)
{
throw new NotSupportedException();
}
if ((bool)e.NewValue)
{
box.TextChanged += TextChanged;
SetHasText(box, !string.IsNullOrEmpty(box.Text));
}
else
{
box.TextChanged -= TextChanged;
}
}
private static void TextChanged(object sender, TextChangedEventArgs e)
{
var box = sender as TextBox;
SetHasText(box, !string.IsNullOrEmpty(box.Text));
}
}
}
{Binding}解释
local:TextBoxHelper.MonitorTextChange="True"
:这是自定义属性local:TextBoxHelper.MonitorTextChange
的设置,是自定义控件或附加属性的一部分。这个属性被用来监测文本的变化。<CheckBox IsChecked="{Binding ElementName=tBox, Path=(local:TextBoxHelper.HasText)}" FontSize="30">
:这是一个复选框控件,其中包含了数据绑定。IsChecked="{Binding ...}"
:这部分指示IsChecked
属性将被绑定到某个数据源。ElementName=tBox
:这是一个Binding的设置,指定了数据源是哪个控件,即名为"tBox"的TextBox控件。Path=(local:TextBoxHelper.HasText)
:这是Binding的路径设置。告诉WPF应用程序查找名为"tBox"的控件,并在该控件上查找名为"HasText"的属性。这个属性用于确定TextBox中是否有文本。
关于这些概念的详细解释:
ElementName
:这是一个Binding设置,用于指定绑定的数据源控件的名称。在示例中,数据源是名为"tBox"的TextBox。Path
:这是用于指定数据源控件上的属性或属性路径的设置。在这里,你正在查找名为"HasText"的属性,该属性被用于确定CheckBox的IsChecked属性。(local:TextBoxHelper.HasText)
:这种写法通常用于引用附加属性,其中local表示当前命名空间,TextBoxHelper是一个附加属性的名称,而HasText是这个附加属性的属性名。
这种绑定方式可以用于将一个控件的属性绑定到另一个控件的属性,使它们保持同步,例如,在文本框中输入文本时,相关的复选框的选中状态也会相应地改变。这种绑定通常用于实现界面元素之间的交互和数据同步。
e.NewValue解释
e.NewValue
是一个 DependencyPropertyChangedEventArgs
对象的属性,它用于存储关于依赖属性更改的信息。
- 含义:
e.NewValue
表示在依赖属性更改时,属性的新值。当一个依赖属性的值发生变化时,e.NewValue
将包含新值,以便可以在事件处理程序中访问并使用它。 - 作用:
e.NewValue
主要用于在属性更改事件处理程序中获取属性的新值。它允许在属性值发生变化时采取相应的操作。例如,可以根据新值来更新界面元素、执行计算或触发其他操作。 - 类型:
e.NewValue
的类型取决于被监测属性的类型。它是一个object
类型,因为它需要能够表示任何类型的值。通常,需要将其转换为适当的类型,以便在代码中使用。这个类型转换通常是基于知道将要更改的属性的类型。例如,在上述代码示例中,似乎假定属性的新值是一个布尔值。
在提供的代码示例中,if ((bool)e.NewValue)
的作用是检查某个依赖属性的新值是否为 true
,以决定是否执行特定的操作。这是一个典型的用例,其中 e.NewValue
用于确定如何响应属性的更改。