我有一个装饰器类,我想在装饰器的孩子周围包裹一个“边框”。 边框有四个边,每个边都是一个 FrameworkElement。 后者可用于各种目的,例如调整大小、装饰等......子项,因此我想向用户公开侧面,因此侧面的 DependencyProperties ,我使用大多数自定义控件来执行此操作。 装饰器如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Shapes;
namespace CustomControlLibrary
{
public class BorderWrapper : Decorator, INotifyPropertyChanged
{
#region DependencyProperties
// Override base Properties
// Summary:
// Sets the Size privately thus making the user unable to set the Size.
public new double Width
{
get { return (double)GetValue(WidthProperty); }
private set { SetValue(WidthProperty, value); }
}
public static readonly new DependencyProperty WidthProperty =
DependencyProperty.Register("Width", typeof(double), typeof(BorderWrapper), new FrameworkPropertyMetadata(
default(double), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public new double Height
{
get { return (double)GetValue(HeightProperty); }
private set { SetValue(HeightProperty, value); }
}
public static readonly new DependencyProperty HeightProperty =
DependencyProperty.Register("Height", typeof(double), typeof(BorderWrapper), new FrameworkPropertyMetadata(
default(double), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
// Wrapper Sides
// Summary:
// Exposes the sides to the user as dependency property of type (FrameworkElement)
private FrameworkElement left = null;
public FrameworkElement Left
{
get { return left; }
set
{
if (value != left)
{
left = value;
OnPropertyChanged();
}
}
}
public FrameworkElement Top
{
get { return (FrameworkElement)GetValue(TopProperty); }
set { SetValue(TopProperty, value); }
}
public static readonly DependencyProperty TopProperty =
DependencyProperty.Register("Top", typeof(FrameworkElement), typeof(BorderWrapper), new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public FrameworkElement Right
{
get { return (FrameworkElement)GetValue(RightProperty); }
set { SetValue(RightProperty, value); }
}
public static readonly DependencyProperty RightProperty =
DependencyProperty.Register("Right", typeof(FrameworkElement), typeof(BorderWrapper), new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public FrameworkElement Bottom
{
get { return (FrameworkElement)GetValue(BottomProperty); }
set { SetValue(BottomProperty, value); }
}
public static readonly DependencyProperty BottomProperty =
DependencyProperty.Register("Bottom", typeof(FrameworkElement), typeof(BorderWrapper), new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
// Layout DependencyProperties
// Summary:
// Border Decorations
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(BorderWrapper), new FrameworkPropertyMetadata(
default(CornerRadius), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public Thickness BorderThickness
{
get { return (Thickness)GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
public static readonly DependencyProperty BorderThicknessProperty =
DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(BorderWrapper), new FrameworkPropertyMetadata(
default(Thickness), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));
public Brush BorderBrush
{
get { return (Brush)GetValue(BorderBrushProperty); }
set { SetValue(BorderBrushProperty, value); }
}
public static readonly DependencyProperty BorderBrushProperty =
DependencyProperty.Register("BorderBrush", typeof(Brush), typeof(BorderWrapper), new FrameworkPropertyMetadata(
default(Brush), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
// Public Members
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public event PropertyChangedEventHandler PropertyChanged;
// Constructers
public BorderWrapper()
{
//Add visuals to the VisualsCollection
AddVisualChild(Left);
AddVisualChild(Top);
AddVisualChild(Right);
AddVisualChild(Bottom);
}
//Override Members
protected override int VisualChildrenCount => 5;
#region Private Methods
// Visuals Measurmment
private Size MeasureVisuals(FrameworkElement child)
{
Trace.WriteLine("MeasureVisuals Called");
Size totalSize = default;
Size childSize = new Size(child.ActualWidth, child.ActualHeight);
child.Measure(childSize);
totalSize = SizeAddition(totalSize, childSize);
if(Left != null)
{
Size leftSide = new Size(BorderThickness.Left, childSize.Height);
Left.Measure(leftSide);
totalSize = SizeAddition(totalSize, leftSide);
}
if(GetValue(TopProperty) != null)
{
Size topSize = new Size(childSize.Width, BorderThickness.Top);
Top.Measure(topSize);
totalSize = SizeAddition(totalSize, topSize);
}
if(GetValue(RightProperty) != null)
{
Size rightSize = new Size(BorderThickness.Right, childSize.Height);
Right.Measure(rightSize);
totalSize = SizeAddition(totalSize, rightSize);
}
if (GetValue(BottomProperty) != null)
{
Size bottomSize = new Size(childSize.Width, BorderThickness.Bottom);
Bottom.Measure(bottomSize);
totalSize = SizeAddition(totalSize, bottomSize);
}
return totalSize;
}
// Visuals Arrangement
private Size ArrangeVisuals(FrameworkElement child)
{
Trace.WriteLine("ArrangeVisuals Called");
Size totalSize = default;
Size childSize = new Size(child.Width, child.Height);// !!
child.Arrange(new Rect(new Point(BorderThickness.Left, BorderThickness.Top), childSize));
Point c_Rel_P_Pos = child.TranslatePoint(new Point(0, 0), this);
totalSize = SizeAddition(totalSize, childSize);
if (Left != null)
{
Size leftSide = new Size(BorderThickness.Left, childSize.Height);
Left.Arrange(new Rect(new Point(c_Rel_P_Pos.X - BorderThickness.Left, c_Rel_P_Pos.Y), leftSide));
totalSize = SizeAddition(totalSize, leftSide);
}
if (GetValue(TopProperty) != null)
{
Size topSize = new Size(childSize.Width, BorderThickness.Top);
Top.Arrange(new Rect(new Point(c_Rel_P_Pos.X, c_Rel_P_Pos.Y - BorderThickness.Top), topSize));
totalSize = SizeAddition(totalSize, topSize);
}
if (GetValue(RightProperty) != null)
{
Size rightSize = new Size(BorderThickness.Right, childSize.Height);
Right.Arrange(new Rect(new Point(c_Rel_P_Pos.X + childSize.Width, c_Rel_P_Pos.Y), rightSize));
totalSize = SizeAddition(totalSize, rightSize);
}
if (GetValue(BottomProperty) != null)
{
Size bottomSize = new Size(childSize.Width, BorderThickness.Bottom);
Bottom.Arrange(new Rect(new Point(c_Rel_P_Pos.X, c_Rel_P_Pos.Y + childSize.Height), bottomSize));
totalSize = SizeAddition(totalSize, bottomSize);
}
return totalSize;
}
#endregion
// Override Methods
protected override Visual GetVisualChild(int index)
{
switch (index)
{
case 0: return Child;
case 1: return Left;
case 2: return Top;
case 3: return Right;
case 4: return Bottom;
default: throw new ArgumentException(index + " index visual Is out of bounds");
}
}
protected override Size MeasureOverride(Size constraint)
{
//Trace.WriteLine("MeasureOverride Called");
Size visualsSize = constraint;
if (Child is FrameworkElement child)
visualsSize = MeasureVisuals(child);
return visualsSize;
}
protected override Size ArrangeOverride(Size arrangeSize)
{
//Trace.WriteLine("ArrangeOverride Called");
Size visualsArrangeSize = arrangeSize;
if (Child is FrameworkElement child)
visualsArrangeSize = ArrangeVisuals(child);
return visualsArrangeSize;
}
private static Size SizeAddition(Size size1, Size size2)
{
return new Size(size1.Width + size2.Width, size1.Height + size2.Width);
}
}
}
和 xaml:
<cc:BorderWrapper BorderThickness="15" HorizontalAlignment="Left"
VerticalAlignment="Top">
<cc:BorderWrapper.Left>
<Rectangle>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</cc:BorderWrapper.Left>
<cc:BorderWrapper.Top>
<Rectangle Fill="Green"/>
</cc:BorderWrapper.Top>
<cc:BorderWrapper.Right>
<Rectangle Fill="DarkCyan"/>
</cc:BorderWrapper.Right>
<cc:BorderWrapper.Bottom>
<Rectangle Fill="DarkMagenta"/>
</cc:BorderWrapper.Bottom>
<Rectangle Width="100" Height="100" Fill="Red"/>
</cc:BorderWrapper>
但是当我将鼠标悬停在左矩形“边框”上时,颜色不会改变。 我做错了什么?
我找到了一个似乎有效的解决方案,通过将“边界”从 DependencyProperties 更改为 Properties,如下所示。
private FrameworkElement _left;
[DefaultValue(null)]
public FrameworkElement Left
{
get { return _left; }
set
{
if (_left != value)
{
RemoveVisualChild(_left);
RemoveLogicalChild(_left);
_left = value;
AddVisualChild(value);
AddLogicalChild(value);
InvalidateMeasure();
}
}
}