C# CoerceValueCallback合并、替换元数据值
static CustomGridViewColumn() { WidthProperty.OverrideMetadata( typeof(CustomGridViewColumn), new FrameworkPropertyMetadata(WidthProperty.DefaultMetadata.DefaultValue, null, OnCoerceWidthValue)); }
?
在OnCoerceWithValue方法中,我们可以这么做
And the OnCoerceWithValue function is as follow.
private static object OnCoerceWidthValue(DependencyObject d, object basevalue) { var column = d as CustomGridViewColumn; if (column == null) { return basevalue; } var width = (double)basevalue; if (column.IsFixedSize) { if (column.FixedWidth > 0) { return column.FixedWidth; } } width = column.MinWidth >= 0 ? Math.Max(width, column.MinWidth) : width; width = column.MaxWidth >= 0 ? Math.Min(width, column.MaxWidth) : width; if (column.IsFixedSize) { if (column.FixedWidth < 1 || double.IsNaN(column.FixedWidth)) { column.FixedWidth = width; } } return width; }
?
如你所示例,扩展类定义了如何确定该列宽度的方法。
As you can see, the extended class has its own way of determine the width of a column;
?
我们还准备了一个例子,该例中,假设我们要写一个名字为Shirt的自定义控件/用户控件,并且当该控件表示的类型没有扣子时,我们提供了该控件扣子类型的默认值。(比如说, ButtonColors.Black 初始值)。
For another example, suppose that we are writing a UserControl/CustomControl, whose name is Shirt, and we have default value for those kind of Shirt w/ buttons (those Shirt has no buttons, we will set the ButtonColor to ButtonColors.Black -- the starting value).
public partial class Shirt : UserControl { #region Dependency Properties public static readonly DependencyProperty ButtonColorProperty = DependencyProperty.Register( "ButtonColor", typeof(ButtonColors), typeof(Shirt), new FrameworkPropertyMetadata(ButtonColors.White, null, CoerceButtonColor) ); private static object CoerceButtonColor(DependencyObject d, object basevalue) { ShirtTypes newShirtType = (d as Shirt).ShirtType; if (newShirtType == ShirtTypes.Dress || newShirtType == ShirtTypes.Bowling) { return ButtonColors.Black; } return ButtonColors.None; } public ButtonColors ButtonColor { get { return (ButtonColors)GetValue(ButtonColorProperty); } set { SetValue(ButtonColorProperty, value); } } public static readonly DependencyProperty ShirtTypeProperty = DependencyProperty.Register( "ShirtType", typeof(ShirtTypes), typeof(Shirt), new FrameworkPropertyMetadata(ShirtTypes.Polo, null) ); public ShirtTypes ShirtType { get { return (ShirtTypes)GetValue(ShirtTypeProperty); } set { SetValue(ShirtTypeProperty, value); } } #endregion Dependency Properties #region Properties #endregion Properties #region Constructors public Shirt() { InitializeComponent(); ButtonColor = ButtonColors.White; ShirtType = ShirtTypes.Polo; } #endregion Constructors }
?
注意上面的CoerceButtonColor函数名,结果是用Shirt的类型决的。
Note the code on name CoerceButtonColor,fthe resulting value is determined by the type of Shirt the control represent.
<UserControl x:/> </UserControl.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <!-- do this: Background="{Binding RelativeSource={RelativeSource AncestorType={x:Type constants:Shirt}}, Path=ButtonColor, Converter={StaticResource ButtonColorConverter}}" do NOt do this: Background="{Binding Source={RelativeSource AncestorType={x:Type constants:Shirt}}, Path=ButtonColor, Converter={StaticResource ButtonColorConverter}}" or do this: Background="{Binding ElementName=_Shirt, Path=ButtonColor, Converter={StaticResource ButtonColorConverter}}" --> <Button x:Name="Button" Background="{Binding RelativeSource={RelativeSource AncestorType={x:Type constants:Shirt}}, Path=ButtonColor, Converter={StaticResource ButtonColorConverter}}" Content="" Grid.Row="0"/> <Label x:Name="Label" Content="Label" Grid.Row="1" /> </Grid></UserControl>
?
该例子中用到的其他类型是
The Supporting classes include
?
public enum ButtonColors { Black, White, None, } public enum ShirtTypes { Dress, Bowling, Polo, } And Converters. public class ButtonColorConverter : System.Windows.Data.IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var buttonColor = (ButtonColors)value; var color = Colors.Red; switch (buttonColor) { case ButtonColors.Black: color = Colors.Aqua; break; case ButtonColors.White: color = Colors.Beige; break; case ButtonColors.None: color = Colors.Blue; break; default: color = Colors.Red; break; } return new SolidColorBrush(color); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
?
所以总的来说,CoerceValueCallback是一个以元数据方式提供给DependencyProperty的方法,利用它可以让程序员合并(或者是替换)元数据的子类DependencyProperty值。 一般来说你可以在如下三总方法中设置回调 1。在新类中定义新的DependencyProperty;2。OverrideMetadata(Type, ProeprtyMetadata)重载已有DependencyProperty的元数据;3。在新类中加入已有类。
So, in conclusion: CoerceValueCallback is the mean provided as a MetaData to the DependencyProperty which allows developer to merge (or replace, which is the default merge logic) in metadata subclass. Generally you can pass in your own Coerce logic in three conditions, 1. Defining a new dependency property on a new class. 2. Override the metadata for an existing dependency with OverrideMetadata(Type, ProeprtyMetadata) property. 3. Add a existing dependency Property to a new DependencyObject class.
参考:
References
the PropertyMetadta.CoerceValueCallback property
CoerceValueCallback Delegate
?