我将使用我的类的简化版本,以避免包含太多信息。我将扩展Canvas的此类设置为主窗口中的DataContext,它使用带属性textBrush的颜色的格式化文本写入“Hello world”。我有一个TextBox,并希望能够通过它更改颜色,但是当属性为?
public class CanvasExtension: INotifyPropertyChanged
{
private SolidColorBrush textBrush
public SolidColorBrush TextBrush
{
get { return textBrush; }
set
{
textBrush= value;
OnPropertyChanged();
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
FormattedText formattedTextInput = new FormattedText("Hello world",System.Globalization.CultureInfo.GetCultureInfo("en-US"),
FlowDirection.LeftToRight, new Typeface("Verdana"), 12, TextBrush, 1);
dc.DrawText(formattedTextInput, 0);
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
主窗口代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = visualTable;
}
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key==Key.Enter)
{
TextBox box = (TexBox)sender;
DependencyProperty property = TextBox.TextProperty;
BindingExpression binding = BindingOperations.GetBindingExpression(box,property);
if (binding != null)
{
binding.UpdateSource();
}
KeyBoard.ClearFocus();
}
}
}
最后,我的Xaml:
<Window x:Class="DrawingTutorial.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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:CanvasExtension x:Name="visualTable"> </local:CanvasExtension>
<TextBox Text="{Binding TextBrush}"></TextBox>
</Grid>
</Window>
我想实现的(我认为应该起作用)是:我在textBox中输入一些颜色,然后按Enter键。然后,TextBrush属性被更新,在这里,因为我已经实现了INotifyPropertyChanged并在setter中抛出了事件,所以我的UI应该更新(被重绘?我不知道在画布的情况下是否是相同的),我应该看到“Hello World”用新颜色书写。然而,这并没有发生(绑定工作,我检查了),直到我显式调用InvalidateVisual(),我相信这超出了INotifyPropertyChanged的目的。有没有方法可以做到这一点,而不必手动重置视觉?注意,如果我在调用OnPropertyChanged()后在setter中添加InvalidateVisual();它会更新UI,也就是我需要的功能。但是,UI是否应该更新,因为我调用了OnPropertyChanged(),程序“知道”它必须更新?
1条答案
按热度按时间qnakjoqk1#
1.必须为
CanvasExtension
控件指定大于0的大小以提供绘图区域。请正确配置Grid
行以允许控件拉伸并防止TextBox
覆盖CanvasExtension
,或者显式设置CanvasExtension.Width
和CanvasExtension.Height
。1.由于
CanvasExtension
是DependencyObject
(它扩展了Canvas
),因此您应该将属性实现为DependencyProperty
,而不是实现INotifyPropertyChanged
。这将提高性能(并增加其他好处)。1.因为您在
UIElement.OnRender
中绘制文本,所以必须调用UIElement.InvalidateVisual
来强制呈现,即在属性更改时调用UIElement.OnRender
。当将
CanvasExtension.TextBrush
属性实现为DependencyProperty
时,如2)中所建议的,可以通过在属性 meta数据上设置FrameworkPropertyMetadataOptions.AffectsRender
标志来配置该属性以强制调用UIElement.OnRender
。1.将
Binding.UpdateSourceTrigger
设置为UpdateSourceTrigger.Explicit
并手动更新Binding.Source
(如您所做的那样),或者直接将焦点从TextBox
移开(推荐)。TextBox.Text
属性的默认Binding.Mode
为BindingMode.LostFocus
。因此,移开焦点将生成最短和最简单的代码。画布扩展名.cs
主窗口.xaml.cs
主窗口.xaml