2016-11-30 238 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