.NET|--WPF|--笔记合集|--依赖项属性|--2.注册依赖项属性

前言


使用一个实例, 其实分2步骤
定义, 实例化.

但是依赖项属性为不能直接实例化, 因为DependencyProperty类没有公开的构造函数,
只能使用静态的DependencyProperty.Register方法创建DependencyProperty实例.

DependencyProperty.Register源码

// System.Windows.DependencyProperty
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
{
	RegisterParameterValidation(name, propertyType, ownerType);
	PropertyMetadata defaultMetadata = null;
	if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
	{
		defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
	}
	DependencyProperty dependencyProperty = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
	if (typeMetadata != null)
	{
		dependencyProperty.OverrideMetadata(ownerType, typeMetadata);
	}
	return dependencyProperty;
}


DependencyProperty.Register在TextBlock源码中使用

public class TextBlock : FrameworkElement // 其它继承的基类省略.
{
	// 第1步:定义依赖项属性
	public static readonly DependencyProperty TextWrappingProperty;
	
	// 第2步:注册依赖项属性( 本篇笔记要讲的 )
	static TextBlock()
	{
		TextWrappingProperty = 
		DependencyProperty.Register
		(
			"TextWrapping", 
			typeof(TextWrapping), //一个枚举类"System.Windows.TextWrapping"
			typeof(TextBlock), 
			new FrameworkPropertyMetadata(TextWrapping.NoWrap, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender), 
			IsValidTextWrap
		);
	}

	// 注册依赖项属性的参数"ValidateValueCallback",用于验证属性值的回调函数.
	private static bool IsValidTextWrap(object o)
	{
		TextWrapping textWrapping = (TextWrapping)o;
		if (textWrapping != TextWrapping.Wrap && textWrapping != TextWrapping.NoWrap)
		{
			return textWrapping == TextWrapping.WrapWithOverflow;
		}
		return true;
	}

	// 第3步:属性包装器( 以后会说,先注册成功了,再说这一步 )
	public TextWrapping TextWrapping
	{
		get
		{
			return (TextWrapping)GetValue(TextWrappingProperty);
		}
		set
		{
			SetValue(TextWrappingProperty, value);
		}
	}
}

DependencyProperty.Register参数介绍

这个方法是 DependencyProperty.Register 方法的实现,用于注册一个新的依赖项属性。这个方法接受五个参数,分别是 namepropertyTypeownerTypetypeMetadatavalidateValueCallback。以下是对这五个参数的详细解释:

1. name (string)
  • 解释:依赖项属性的名称。
  • 用途:这是依赖项属性的标识符,用于在代码和XAML中引用该属性。它必须是唯一的,以避免冲突。
2. propertyType (Type)
  • 解释:依赖项属性的类型。
  • 用途:指定该依赖项属性能够存储的数据类型。例如,可以是 intdoublestringBrush 等等。这决定了属性可以接受和返回的数据类型。
3. ownerType (Type)
  • 解释:定义依赖项属性的所有者类型。
  • 用途:指示哪个类拥有这个依赖项属性。通常是控件或其他 DependencyObject 派生类。这也用于查找属性的默认值和元数据。
4. typeMetadata (PropertyMetadata)
  • 解释:属性元数据,包括默认值、回调函数和其他属性行为信息。
  • 用途:提供有关属性的附加信息,如默认值、属性改变时的回调、属性影响的布局行为等。这些元数据定义了属性的行为特性。
  • 源码: public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback)...先知道主要有这3个参数, 关于这个PropertyMetadata,开始单独做篇笔记.
  • 疑问:属性元数据的默认值和依赖项属性的值, 有关系不?
5. validateValueCallback (ValidateValueCallback)
  • 解释:用于验证属性值的回调函数。
  • 用途:这是一个委托,用于验证传递给依赖项属性的值是否有效。通过这个回调,可以确保设置到属性上的值符合预期,例如值在一定范围内或满足特定条件。
方法详细解释
  • 参数验证:首先,RegisterParameterValidation 方法用于验证 namepropertyTypeownerType 参数是否有效。这是为了确保参数的正确性和有效性。
  • 默认元数据处理:接下来,方法检查 typeMetadata 是否不为空以及其 DefaultValueWasSet 方法是否返回 true。如果设置了默认值,则创建一个新的 PropertyMetadata 对象,将 typeMetadata 的默认值作为参数传递。
  • 注册属性RegisterCommon 方法用于实际注册属性,返回一个新的 DependencyProperty 实例。这个方法包含了处理属性注册的核心逻辑。
  • 覆盖元数据:如果 typeMetadata 不为空,则调用 OverrideMetadata 方法,将元数据应用到 DependencyProperty 上,以便为特定所有者类型提供特定的行为。
示例

假设我们要注册一个新的依赖项属性 HighlightColor,该属性类型是 Brush,所有者类型是 TextBlock,并且有一个默认值 null。我们还可以提供一个值验证回调来确保只有特定类型的值可以赋给这个属性。

public static readonly DependencyProperty HighlightColorProperty = DependencyProperty.Register(
    "HighlightColor",                         // 属性名称
    typeof(Brush),                            // 属性类型
    typeof(TextBlock),                        // 所有者类型
    new PropertyMetadata(null),               // 属性元数据,默认值为 null
    new ValidateValueCallback(ValidateColor)  // 值验证回调函数
);

// 验证回调函数
private static bool ValidateColor(object value)
{
    return value == null || value is Brush;
}
总结

DependencyProperty.Register 方法的五个参数分别定义了依赖项属性的名称、类型、所有者、元数据和验证逻辑。
通过这些参数,可以详细定义和控制依赖项属性的行为,确保其在应用程序中唯一且高效地工作。

System.Windows.Controls.TextBlock中注册依赖项属性


// 定义依赖项属性
public static readonly DependencyProperty TextProperty;

static TextBlock()
{
        // 注册依赖项属性
        TextProperty = DependencyProperty.Register
        (
        "Text", 
        typeof(string), 
        typeof(TextBlock), 
        new FrameworkPropertyMetadata
            (
                string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, 
                OnTextChanged, 
                CoerceText
            )
        );
}

自己注册一个依赖项属性

# 使用LINQPad运行

/*
注意事项 : 
不能直接启动(F5), 
多次直接启动(F5)会报错 : "不能在同一 AppDomain 中创建多个 System.Windows.Application 实例。"

当报错的时候,有2种解决方案 : 

1.使用"菜单栏--Query--Kill Process and Execute"

2.更改设置 : 
Edit -- Preference -- Advanced -- Execution
Always use Fresh Process per Execution


这2种方法, "kill Process and Execute"和"Always use Fresh Process per Execution",
其实意思是一样~

*/

/*

*/


#region 测试方法

internal void Test()
{
	System.Windows.Controls.Image image = new System.Windows.Controls.Image();
	System.Windows.DependencyObject dependencyObject;
	System.Windows.DependencyProperty dependencyProperty;
	//System.Windows.DependencyProperty dp = new System.Windows.DependencyProperty();
}

#endregion

#region 注册

// 注册
public static readonly System.Windows.DependencyProperty HighlightColorProperty = System.Windows.DependencyProperty.Register
(
	"HighlightColor",										// 属性名称,如果名称是"Text",则会报错:“Text”属性已由“TextBlock”注册。
	typeof(string),                            				// 属性类型
	typeof(System.Windows.Controls.TextBlock),				// 所有者类型,如果使用非派生自DependencyObject的,则会报错":“XXXX”类型必须派生自 DependencyObject。
	new System.Windows.PropertyMetadata(null),				// 属性元数据,默认值为 null
	new System.Windows.ValidateValueCallback(ValidateColor)	// 值验证回调函数
);

// 验证回调函数
private static bool ValidateColor(object value)
{
	return true;
	// 可以增加自己的验证,比如下面的验证↓
	//return value == null || value is System.Windows.Media.Brush;
}


#endregion
// 程序入口
void Main()
{

	System.Windows.Application app = new System.Windows.Application();
	var mainWindow = new MainWindows
	{
		Title = "Main Window",
		Width = 960,
		Height = 400,
		WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen
	};
	app.Run(mainWindow);
}

// 主窗口
public class MainWindows : System.Windows.Window
{
	public MainWindows()
	{
		Init();
	}

	public void Init()
	{
		// 创建一个Grid
		System.Windows.Controls.Grid grid = new System.Windows.Controls.Grid();

		// 创建一个TextBlock
		System.Windows.Controls.TextBlock textBlock = new System.Windows.Controls.TextBlock
		{
			Text = "依赖项属性,\r\n 注册成功 \r\n --zh89233",
		};

		// 将TextBlock添加到Grid
		grid.Children.Add(textBlock);
		// 将Grid设置为Window的内容
		this.Content = grid;
	}
}



a89b6220001a1bb9e7b07cf795065621.png

结尾

其实注册方法, 看着简单, 但是毕竟有5个参数, 
我当时第一次注册时候, 因为参数总是有问题, 我根据提示进行修改后才注册成功的,
大家也可以试试, 真正的让代码运行起来, 能运行到定义和注册, 
就先运行到这里, 到这一步运行对了, 再说下一步. 

其实AI确实能提高学习效率, 以前看不懂的地方, 问一下,
回答的还是有鼻子有眼的, 
特别是书里有些作者的想要表达的"思想感情",真的一下读不出来...

posted @ 2024-08-31 10:52  zh89233  阅读(18)  评论(0编辑  收藏  举报