C# 属性设置程序在XAML中不工作
有一个从画布扩展而来的自定义控件,它只能接受类Shape的实例作为其子级。考虑下面的代码:C# 属性设置程序在XAML中不工作,c#,wpf,xaml,C#,Wpf,Xaml,有一个从画布扩展而来的自定义控件,它只能接受类Shape的实例作为其子级。考虑下面的代码: public class SvgGroup : Canvas { // ... public Brush Fill { // Retuns the fill brush value of all the shape children, if they are all the same. Otherwise, the default value of Brush
public class SvgGroup : Canvas
{
// ...
public Brush Fill
{
// Retuns the fill brush value of all the shape children, if they are all the same. Otherwise, the default value of Brush is returned
get
{
Brush rtn = default(Brush);
for (int i = 0; i < ShapeChildren.Count; i++)
{
Shape shape = ShapeChildren[i];
if (i == 0) // First loop
{
rtn = shape.Fill;
}
else if (rtn != shape.Fill) // Children shapes have different Fill value
{
return default(Brush);
}
}
return rtn;
}
// Sets the fill brush value of all the shape children
set
{
foreach (Shape shape in ShapeChildren)
{
shape.Fill = value;
}
}
}
// ...
}
问题是,在XAML中设置Fill属性时,什么都不会发生。但是,设置隐藏的填充代码是可行的
我考虑的是依赖属性,但是在这个场景中的实现可能会非常棘手。我认为您应该定义两个依赖属性,并且应该更新其中一个:
public class SvgGroup : Canvas
{
public Brush Fill
{
get { return (Brush)GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
}
public static readonly DependencyProperty FillProperty
= DependencyProperty.Register(
"Fill",
typeof(Brush),
typeof(SvgGroup),
new FrameworkPropertyMetadata(Brushes.Red, OnFillPropertyChanged)
);
private static void OnFillPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SvgGroup svg = (SvgGroup)d;
if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
{
foreach (Shape shape in d.ShapeChildren)
{
shape.Fill = (Brush)e.NewValue;
}
d.OnShapeBrushChanged(); // Note that you should call this method in some other places too.
}
}
public Brush FillDifferentBrush
{
get { return (Brush)GetValue(IsFillDifferentProperty); }
}
public static readonly DependencyProperty FillDifferentProperty
= DependencyProperty.Register(
"FillDifferentBrush",
typeof(Brush),
typeof(SvgGroup),
new PropertyMetadata(null)
);
void OnShapeBrushChanged()
{
Brush rtn = default(Brush);
for (int i = 0; i < ShapeChildren.Count; i++)
{
Shape shape = ShapeChildren[i];
if (i == 0) // First loop
{
rtn = shape.Fill;
}
else if (rtn != shape.Fill) // Children shapes have different Fill value
{
SetValue(FillDifferentProperty, default(Brush));
}
else
SetValue(FillDifferentProperty, rtn);
}
}
}
您应该正确调用OnShapeBrushChanged,例如,当您添加新形状或单独更改其笔刷时,或者当您调用Fill属性以保持其更新时,例如ItemsControl的HasItems属性。您可以声明一个with行为
在任何父元素上设置属性时,其值将由所有子元素继承。有一个PropertyChanged回调,用于检查元素是否为形状,并最终将继承的笔刷应用于形状的Fill属性
public static class ChildFillEx
{
public static readonly DependencyProperty ChildFillProperty =
DependencyProperty.RegisterAttached(
"ChildFill", typeof(Brush), typeof(ChildFillEx),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.Inherits,
ChildFillPropertyChanged));
public static Brush GetChildFill(DependencyObject obj)
{
return (Brush)obj.GetValue(ChildFillProperty);
}
public static void SetChildFill(DependencyObject obj, Brush value)
{
obj.SetValue(ChildFillProperty, value);
}
private static void ChildFillPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var shape = obj as Shape;
if (shape != null)
{
shape.Fill = (Brush)e.NewValue;
}
}
}
您可以这样使用它:
<Canvas local:ChildFillEx.ChildFill="Red">
<Rectangle Width="100" Height="100" />
</Canvas>
您不会设置SvgGroup.Fill was set之后添加的任何子级的Fill属性。如果设置为true,则解析XAML时会发生这种情况。这就是为什么我在想DependencyProperty这会有什么帮助?设置填充后,您仍然需要对添加的子元素作出反应。是否有方法可以侦听形状子元素笔刷中的更改?我不确定。但是,不要让用户直接更改特定形状的笔刷。为此目的创建一个公共方法。除此之外,您应该在两种情况下检查画笔:添加/删除新项目时和设置Fill属性时。IsFillDifferentBrush的用途是什么?这似乎完全是多余的。您也没有解释它的用法,也没有在代码示例中实际使用它。除此之外,您不遵守依赖项属性命名约定。当属性为IsFillDifferentitBrush时,DependencyProperty字段应命名为IsFillDifferentitBrushProperty,传递给register的名称必须为IsFillDifferentitBrush。@Clemens这是一个输入错误。这是一个画笔,而不是一个布尔,因为它是设置在onshapebrush方法。我会编辑。OP的用例永远不需要两个属性。你真正需要的是一个事件或类似的事情来对增加的孩子做出反应。嗨,一个相关的问题:你同意吗?谢天谢地。例如,考虑附加的行为。但是,具有值继承的依赖属性通常应声明为附加属性。请参阅此处的“创建自定义属性可继承”部分:的确,这是一个有趣的概念,我们将尝试一下,看看它是否可以应用于我的情况