wpf附加属性详解
为什么使用附加属性
附加属性的一个用途是允许不同的子元素为父元素中定义的属性指定唯一的值。 此方案的一个具体应用是,让子元素通知父元素它们在用户界面 (UI) 中的呈现方式。 一个示例是 DockPanel.Dock 属性。 该 DockPanel.Dock 属性是作为附加属性创建的,因为它设计为在中包含的元素上设置,而不是在自身中包含的元素上设置 DockPanel DockPanel 。 DockPanel类定义 DependencyProperty 名为的静态字段 DockProperty ,然后提供 GetDock 和 SetDock 方法作为附加属性的公共访问器。
一、附加属性的特点
1、特殊的依赖属性
2、用于非定义该属性的类 例如Grid面板的RowDefinition、ColumnDefinition、Canvas面板的Left、Right,DockPanel面板的Dock都是附加属性。
二、附加属性的定义
1、声明数据属性变量。 public static 的DependencyProperty类型的变量。
2、在属性系统中进行注册,使用DependencyProperty.RegisterAttached()方法来注册,方法参数和注册依赖属性时Register()方法的参数一致。
3、调用静态方法设置和获取属性值。通过调用DependencyObject的SetValue()和GetValue()方法来设置和获取属性的值。两个方法应该命名为SetPropertyName()方法和GetPropertyName()方法。
三、示例(给页面上的Grid表格控件做特殊边框样式)
创建帮助类定义并注册附加属性:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Opacs.Client.Utilities
{
public static class GridHelper
{
public static bool GetShowBorder(DependencyObject obj)
{
return (bool)obj.GetValue(ShowBorderProperty);
}
public static void SetShowBorder(DependencyObject obj, bool value)
{
obj.SetValue(ShowBorderProperty, value);
}
public static readonly DependencyProperty ShowBorderProperty =
DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridHelper), new PropertyMetadata(OnShowBorderChanged));
private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var grid = d as Grid;
if ((bool)e.OldValue)
{
grid.Initialized -= (s, arg) => { };
}
if ((bool)e.NewValue)
{
grid.Initialized += (s, arg) =>
{
var controls = grid.Children;
var count = controls.Count;
for (var i = 0; i < count; i++)
{
var item = controls[i] as FrameworkElement;
#region 单元格边框Thickness详细设计
var rowCount = grid.RowDefinitions.Count;
var columnCount = grid.ColumnDefinitions.Count;
var row = Grid.GetRow(item);
var column = Grid.GetColumn(item);
var rowspan = Grid.GetRowSpan(item);
var columnspan = Grid.GetColumnSpan(item);
var thicknessValue = 1;
var thickness = new Thickness(thicknessValue);
var thicknessColor = Colors.DarkGray;
var background = new SolidColorBrush(Colors.White);
if (row == 0)
{
background = new SolidColorBrush(Colors.LightGray);
}
if (row > 0 && row <= rowCount - 1)
{
thickness.Top = 0;
}
if (column > 0 && column <= columnCount - 1)
{
thickness.Left = 0;
}
item.BorderThicknessRemove(ref thickness);
#endregion
var border = new Border()
{
BorderBrush = new SolidColorBrush(thicknessColor),
BorderThickness = thickness,
Background = background
};
Grid.SetRow(border, row);
Grid.SetColumn(border, column);
Grid.SetRowSpan(border, rowspan);
Grid.SetColumnSpan(border, columnspan);
grid.Children.RemoveAt(i);
border.Child = item;
grid.Children.Insert(i, border);
}
};
}
}
public static void BorderThicknessRemove(this FrameworkElement item, ref Thickness thickness)
{
if (item.Tag != null)
{
if (item.Tag.Equals("LeftWideBorder"))
{
thickness.Left = 0;
}
if (item.Tag.Equals("RightWideBorder"))
{
thickness.Right = 0;
}
}
}
}
}
在xaml页面上使用附加属性:
<dxwui:NavigationPage
x:Class="Opacs.Client.Views.UserCheck.OptometryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:utilities="clr-namespace:Opacs.Client.Utilities">
<Grid
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
utilities:GridHelper.ShowBorder="True"> //功能是给grid表格添加自定义的边框
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
TextAlignment="Center"
TextWrapping="Wrap" />
</Grid>
<dxwui:NavigationPage>
四、附加属性的另外一种用法:
定义附加属性类
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.Input;
using System.Windows.Media;
namespace Demo3.Control
{
public class ControlAttachProperty
{
#region 圆角
public static CornerRadius GetCornerRadius(DependencyObject obj)
{
return (CornerRadius)obj.GetValue(CornerRadiusProperty);
}
public static void SetCornerRadius(DependencyObject obj, CornerRadius value)
{
obj.SetValue(CornerRadiusProperty, value);
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(ControlAttachProperty), new PropertyMetadata(null));
#endregion
}
}
在xaml页面使用它:
给自定义的附加属性赋值
<Window x:Class="Demo3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Demo3.Control"
Background="Black"
Title="MainWindow"
WindowStartupLocation="CenterScreen"
Height="350"
Width="525">
<StackPanel>
<TextBox x:Name="UserName"
Width="230"
Height="38"
Margin="0,20,0,0"
FontSize="18"
VerticalContentAlignment="Center"
c:ControlAttachProperty.CornerRadius="5" /> //给自定义的附加属性赋值
Style="{StaticResource DefaultTextBox}"
</StackPanel>
</Window>
在style文件中进行使用
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:c="clr-namespace:Demo3.Control"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Demo3;component/Resources/Style/DeleteButton.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--TextBox默认样式-->
<Style x:Key="DefaultTextBox" TargetType="{x:Type TextBox}">
<Setter Property="ContextMenu" Value="{DynamicResource TextBoxContextMenu}" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="Bg"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
CornerRadius="{TemplateBinding c:ControlAttachProperty.CornerRadius}" //这里的Border控件的CornerRadius属性的值=(TemplateBinding)父级的c:ControlAttachProperty.CornerRadius附加属性的值=5
Background="White"
BorderBrush="Transparent"
BorderThickness="0">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>