wpf 尽管调用了OnPropertyChanged,但绑定到画笔的TextBox仍不更新UI

iklwldmw  于 2022-11-26  发布在  其他
关注(0)|答案(1)|浏览(325)

我将使用我的类的简化版本,以避免包含太多信息。我将扩展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(),程序“知道”它必须更新?

qnakjoqk

qnakjoqk1#

1.必须为CanvasExtension控件指定大于0的大小以提供绘图区域。请正确配置Grid行以允许控件拉伸并防止TextBox覆盖CanvasExtension,或者显式设置CanvasExtension.WidthCanvasExtension.Height
1.由于CanvasExtensionDependencyObject(它扩展了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.ModeBindingMode.LostFocus。因此,移开焦点将生成最短和最简单的代码。

画布扩展名.cs

public class CanvasExtension : Canvas
{
  public SolidColorBrush TextBrush
  {
    get => (SolidColorBrush)GetValue(TextBrushProperty);
    set => SetValue(TextBrushProperty, value);
  }

  public static readonly DependencyProperty TextBrushProperty = DependencyProperty.Register(
    "TextBrush",
    typeof(SolidColorBrush),
    typeof(CanvasExtension),
    new FrameworkPropertyMetadata(
      default(SolidColorBrush), 
      FrameworkPropertyMetadataOptions.AffectsRender));
    
  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, 
      this.TextBrush, 
      1);
    dc.DrawText(formattedTextInput, new Point(0, 0));
  }
}

主窗口.xaml.cs

partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
  }

  private void TextBox_KeyDown(object sender, KeyEventArgs e)
  {
    switch (e.Key)
    {
      // Update TextBox.Text binding
      case Key.Enter:
        (sender as FrameworkElement).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));  
        break;
    }
  }
}

主窗口.xaml

<Window>
  <StackPanel>
    <local:CanvasExtension x:Name="visualTable"
                           Height="200"
                           Width="200" 
                           HorizontalAlignment="Left"/>

    <TextBox PreviewKeyDown="TextBox_KeyDown" 
             Text="{Binding ElementName=visualTable, Path=TextBrush}" />
  </StackPanel>
</Window>

相关问题