I've defined two UserControls
:
CustomCanvas
that derives from Canvas
.Button
and is used to change the GlobalThickness
property in MyViewModel.cs
The CustomCanvas
has a custom dependency property named Thickness
. This is bound to GlobalThickness
in XAML.
I have also overridden the OnRender
method in CustomCanvas
to draw a Rectangle
using a Pen
its thickness is set to Thickness
.
When I click the Button
, the GlobalThickness
changes and the Thickness
which is bound to it changed as well. But I don't get a Rectangle
with a new Thickness
.
Here is all the code I've put together so far.
<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));
}
}
}
This alternative might be more efficient. Instead of frequently calling OnRender
and re-rendering everything each time the Pen Thickness changed, it just changes the Pen's Thickness of an existing rendering which is made only once. The visual output will be updated automatically by 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;
}
}