2016-11-30 35 views
3

WPF自定义控件可跟踪视图模型子属性更改以自动重新提交自身吗?WPF自定义控件重新渲染视图模型子属性更改

比方说,我有两个属性的模型:

public class FullName : ViewModel 
{ 
    string _first; 
    string _last; 

    public string First 
    { 
     get { return _first; } 
     set 
     { 
      _first = value; 
      RaisePropertyChanged(); 
     } 
    } 

    public string Last 
    { 
     get { return _last; } 
     set 
     { 
      _last = value; 
      RaisePropertyChanged(); 
     } 
    } 
} 

其中ViewModel是:

public abstract class ViewModel : INotifyPropertyChanged 
{ 
    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) => 
     OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) => 
     PropertyChanged?.Invoke(this, e); 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

我想对WPF自定义控件依赖属性(AffectsRender,无SubPropertiesDoNotAffectRender)以这种方式参照模型,使得控制在FirstLast属性变化上自动重投:

public class Tag : Control 
{ 
    public static readonly DependencyProperty FullNameProperty = 
     DependencyProperty.Register("FullName", typeof(FullName), typeof(Tag), 
      new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public FullName FullName 
    { 
     get { return (FullName)GetValue(FullNameProperty); } 
     set { SetValue(FullNameProperty, value); } 
    } 

    protected override void OnRender(DrawingContext drawingContext) 
    { 
     base.OnRender(drawingContext); 
     if (FullName == null) 
      return; 

     FontFamily courier = new FontFamily("Courier New"); 
     Typeface courierTypeface = new Typeface(courier, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); 
     FormattedText ft2 = new FormattedText(FullName.First + " " + FullName.Last, 
              CultureInfo.CurrentCulture, 
              FlowDirection.LeftToRight, 
              courierTypeface, 
              14.0, 
              Brushes.Black); 

     drawingContext.DrawText(ft2, new Point()); 
    } 
} 

下面是测试它的片断:

<Window x:Class="WpfApplication3.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:WpfApplication3" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="139.9" Width="249.514"> 
    <StackPanel> 
    <StackPanel.DataContext> 
     <local:FullName> 
      <local:FullName.First>John</local:FullName.First> 
      <local:FullName.Last>Doe</local:FullName.Last> 
     </local:FullName> 
    </StackPanel.DataContext> 
    <local:Tag FullName="{Binding}" Height="20"/> 
    <TextBox Text="{Binding First, UpdateSourceTrigger=PropertyChanged}"/> 
    <TextBox Text="{Binding Last, UpdateSourceTrigger=PropertyChanged}"/> 
    </StackPanel> 
</Window> 

不幸的是,这是行不通的 - 更改不会传播到自定义控制。它可以有效地完成吗?那么SubPropertiesDoNotAffectRender是什么?

+0

@nkoniishvt其实,请看看'标签。 OnRender',绘制'FullName.First +“”+ FullName.Last'。我需要的是完全“所有者绘制的”图表组件(不涉及模板或继承)来显示动态可更新视图模型对象图的内容。我得到了一个印象,即控制跟踪模型子属性的变化没有'SubPropertiesDoNotAffectRender'显式抑制,但它不起作用。 –

回答

1

要使用此功能,您的FullName类必须是Freezable,并且您的FirstLast属性必须是依赖项属性。

你可以看看在DependencyObjectcurrent implementation

internal void NotifySubPropertyChange(DependencyProperty dp) 
{ 
    InvalidateSubProperty(dp); 

    // if the target is a Freezable, call FireChanged to kick off 
    // notifications to the Freezable's parent chain. 
    Freezable freezable = this as Freezable; 
    if (freezable != null) 
    { 
     freezable.FireChanged(); 
    } 
} 

这一机制原本是不打算观察绑定视图模型的子属性。通过观察Freezable的属性并在触发对其属性和子属性进行更改时触发适当的操作,可以简化测量,排列和渲染。

你可以找到一个很好的博客文章here,说明如何做保留图形系统WPF中工作,以及如何使用您感兴趣的功能。

+0

有没有官方的方式来调用'NotifySubPropertyChange'当我的''FreeFreezable'类型属性更改?我已经使用代码反射[这里](http://codereview.stackexchange.com/questions/149059/automatic-redrawing-in-wpf),但它是缓慢和危险的... –

+1

@DmitryNogin,AFAIK有没有办法做到这一点。为了加快通过反射的方法调用,可以按照[本文]中的描述缓存“委托”(https://codeblog.jonskeet.uk/2008/08/09/making-reflection-fly-and-exploring-代表/)。但是,依赖.NET Framework的内部方法并不是编写可维护和可靠代码的好方法,因此我不建议这样做。 – dymanoid

相关问题