Я могу успешно нарисовать часть пользовательского элемента управления в методе OnApplyTemplate
элемента управления, однако этот метод вызывается только один раз и, по-видимому, не вызывается при вызове ApplyTemplate
при изменении свойства элемента управления Num
.
Вот код пользовательского элемента управления:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Cc1
{
public class CirclesControl : Control
{
static CirclesControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CirclesControl), new FrameworkPropertyMetadata(typeof(CirclesControl)));
}
public int Num
{
get { return (int)GetValue(NumProperty); }
set { SetValue(NumProperty, value); }
}
public static readonly DependencyProperty NumProperty =
DependencyProperty.Register("Num", typeof(int), typeof(CirclesControl), new PropertyMetadata(2, new PropertyChangedCallback(OnNumChanged)));
private static void OnNumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CirclesControl control)
{
System.Diagnostics.Debug.WriteLine($"Num changed - value is now {control.Num}");
control.ApplyTemplate();
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var canvasPart = Template.FindName("Part_Canvas", this);
if (canvasPart is Canvas canvas)
{
for (int i = 0; i < Num; i++)
{
var circle = new Ellipse
{
Height = 50,
Width = 50,
Fill = Brushes.Red,
Stroke = Brushes.Green
};
canvas.Children.Add(circle);
Canvas.SetLeft(circle, i * 55);
Canvas.SetTop(circle, 50);
}
}
}
}
}
Я знаю, что OnNumChanged
вызывается, потому что System.Diagnostics.Debug.WriteLine
записывает сообщение в окно вывода. OnNumChanged
также вызывает ApplyTemplate
, но это не вызывает OnApplyTemplate
для вызова.
Вот xaml главного окна:
<Window x:Class="Cc1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Cc1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="1024">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel>
<TextBlock Text="{Binding NumberOfCircles}" FontSize="36"/>
<local:CirclesControl Num="{Binding NumberOfCircles}"/>
</StackPanel>
</Window>
generic.xaml
для контроля:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Cc1">
<Style TargetType="{x:Type local:CirclesControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CirclesControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Canvas x:Name="Part_Canvas"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
И модель представления:
using System;
using System.Windows;
using System.Windows.Threading;
namespace Cc1
{
public class ViewModel : DependencyObject
{
public ViewModel()
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(500)
};
timer.Tick += (s, e) =>
{
NumberOfCircles++;
if (NumberOfCircles == 10)
{
NumberOfCircles = 2;
}
};
timer.Start();
}
public int NumberOfCircles
{
get { return (int)GetValue(NumberOfCirclesProperty); }
set { SetValue(NumberOfCirclesProperty, value); }
}
public static readonly DependencyProperty NumberOfCirclesProperty =
DependencyProperty.Register("NumberOfCircles", typeof(int), typeof(ViewModel), new PropertyMetadata(4));
}
}
Количество кругов (в модели вида) постоянно меняется (это то, что делает таймер диспетчера). TextBlock
в главных окнах точно отражает количество кругов, однако пользовательский элемент управления CirclesControl
в главном окне не обновляется.
Благодарен за любые подсказки относительно того, чего не хватает.