我定义了两个UserControls
:
- 绘图:包含
CustomCanvas
,源自Canvas
。 - 控件:包含
Button
,用于更改MyViewModel.cs
中的
GlobalThickness
属性。CustomCanvas
有一个名为Thickness
的自定义依赖属性。这在XAML中被绑定到GlobalThickness
。
我还覆盖了CustomCanvas
中的OnRender
方法,使用Pen
绘制Rectangle
,其厚度设置为Thickness
。
当我点击Button
时,GlobalThickness
改变了,绑定到它的Thickness
也改变了。但是我没有得到一个新的Thickness
的Rectangle
。
这是我目前整理的所有代码。
<Window x:Class="WpfApplication23.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication23">
<Window.DataContext>
<local:MyViewModel></local:MyViewModel>
</Window.DataContext>
<StackPanel>
<local:Drawing/>
<local:Control/>
</StackPanel>
</Window>
<UserControl x:Class="WpfApplication23.Drawing"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:wpfApplication23="clr-namespace:WpfApplication23">
<Grid>
<wpfApplication23:CustomCanvas Thickness="{Binding GlobalThickness}"
Height="100"
Width="100"
Background="Blue"/>
</Grid>
</UserControl>
<UserControl x:Class="WpfApplication23.Control"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Button Content="Change Thickness"
Width="200"
Height="30"
Click="ButtonBase_OnClick"/>
</StackPanel>
</UserControl>
public partial class Control
{
public Control()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var vm = (MyViewModel)DataContext;
vm.GlobalThickness = 10;
}
}
public class CustomCanvas : Canvas
{
public int Thickness
{
private get { return (int)GetValue(ThicknessProperty); }
set
{
SetValue(ThicknessProperty, value);
InvalidateVisual();
}
}
public static readonly DependencyProperty ThicknessProperty =
DependencyProperty.Register("Thickness", typeof(int), typeof(CustomCanvas), new PropertyMetadata(0));
protected override void OnRender(DrawingContext dc)
{
var myPen = new Pen(Brushes.Red, Thickness);
var myRect = new Rect(0, 0, 400, 400);
dc.DrawRectangle(null, myPen, myRect);
}
}
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private double _globalThickness = 1;
public double GlobalThickness
{
get { return _globalThickness; }
set
{
_globalThickness = value;
RaisePropertyChanged("GlobalThickness");
}
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
这种替代方法可能更有效。而不是频繁调用OnRender
和重新渲染每一次钢笔的厚度改变,它只是改变钢笔的厚度,现有的渲染只做一次。视觉输出将由WPF自动更新。
public class CustomCanvas : Canvas
{
private readonly Pen pen = new Pen(Brushes.Red, 0d);
public static readonly DependencyProperty ThicknessProperty =
DependencyProperty.Register(
"Thickness", typeof(double), typeof(CustomCanvas),
new PropertyMetadata(ThicknessPropertyChanged));
public double Thickness
{
get { return (double)GetValue(ThicknessProperty); }
set { SetValue(ThicknessProperty, value); }
}
protected override void OnRender(DrawingContext drawingContext)
{
var myRect = ...
drawingContext.DrawRectangle(null, pen, myRect);
}
private static void ThicknessPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
((CustomCanvas)obj).pen.Thickness = (double)e.NewValue;
}
}
当绑定设置属性时,不会调用属性setter和InvalidateVisual();
。原因在XAML加载和依赖属性中有解释。
你可以用你的依赖属性注册属性元数据,当属性值改变时强制重新呈现:
public static readonly DependencyProperty ThicknessProperty =
DependencyProperty.Register(
"Thickness", typeof(int), typeof(CustomCanvas),
new FrameworkPropertyMetadata(
default(int), FrameworkPropertyMetadataOptions.AffectsRender));
为什么Thickness
是整数?也可以是double
:
public static readonly DependencyProperty ThicknessProperty =
DependencyProperty.Register(
"Thickness", typeof(double), typeof(CustomCanvas),
new FrameworkPropertyMetadata(
default(double), FrameworkPropertyMetadataOptions.AffectsRender));
public double Thickness
{
get { return (double)GetValue(ThicknessProperty); }
set { SetValue(ThicknessProperty, value); }
}