2016-11-30 6 views
3

Kann WPF Custom Control Trace-Ansicht Modell-Untereigenschaften ändert sich selbst neu zu rendern?WPF Custom Control rerdering auf Ansicht Modell-Untereigenschaften ändern

Lassen Sie uns sagen, dass ich ein Modell mit zwei Eigenschaften haben:

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(); 
     } 
    } 
} 

Wo ViewModel ist:

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; 
} 

Ich möchte eine Abhängigkeitseigenschaft auf der WPF Custom Control haben (AffectsRender, nein SubPropertiesDoNotAffectRender), um das Modell so zu referenzieren, dass die Steuerung automatisch auf First und Last umwandelt:

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()); 
    } 
} 

Hier ist das Snippet zu testen:

<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> 

Leider funktioniert es nicht - Änderungen nicht auf die individuelle Steuerung propagieren. Kann es effizient gemacht werden? Was ist das SubPropertiesDoNotAffectRender dann?

+0

@nkoniishvt Eigentlich einen Blick auf 'Tag, bitte haben. OnRender', der 'FullName.First +" "+ FullName.Last' zeichnet. Was ich brauche, ist eine vollständig "vom Eigentümer gezeichnete" Diagrammkomponente (keine Vorlagen oder Vererbung beteiligt), um den Inhalt des dynamisch aktualisierbaren Diagramms des Ansichtsmodellobjekts anzuzeigen. Ich habe den Eindruck, dass die Kontrolle die Untereigenschaften von Modellen verändert, ohne dass diese explizit durch 'SubPropertiesDoNotAffectRender' unterdrückt werden, aber das funktioniert nicht. –

Antwort

1

Damit dies funktioniert, Ihre FullName Klasse hat eine Freezable und Ihre First und Last Eigenschaften sein müssen Abhängigkeitseigenschaften sein.

Sie könnten am current implementation der DependencyObject einen Blick:

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(); 
    } 
} 

Dieser Mechanismus wurde ursprünglich nicht beabsichtigt, für die Unter Eigenschaften eines gebundenen Ansicht-Modell zu beobachten. Es vereinfacht das FrameworkElement s Messen, Arrangieren und Rendern durch Beobachten der Freezable s'-Eigenschaften und Auslösen geeigneter Aktionen beim Ändern ihrer Eigenschaften und Untereigenschaften.

Sie können eine schöne Blog-Post here, der erklärt, finden wie funktioniert das gehaltene Grafiksystem in WPF Arbeit und wie Sie die Funktion, die Sie interessiert sind, zu verwenden.

+0

Gibt es eine offizielle Möglichkeit, 'NotifySubPropertyChange' aufzurufen, wenn sich meine nicht' 'Freezable' 'getippte Eigenschaft ändert? Ich habe Code-Reflexion [hier] (http://codereview.stackexchange.com/questions/149059/automatic-redrawing-in-wpf) verwendet, aber es ist langsam und gefährlich ... –

+1

@DmitryNogin, AFAIK gibt es keine Möglichkeit, das zu tun . Um den Methodenaufruf über Reflektion zu beschleunigen, können Sie einen 'delegate' zwischenspeichern, wie in [diesem Artikel] beschrieben (https://codeblog.jonskeet.uk/2008/08/09/making-reflection-fly-and-exploring- Delegierte /). Sich auf interne Methoden von .NET Framework zu verlassen, ist jedoch keine gute Möglichkeit, wartbaren und zuverlässigen Code zu schreiben. Daher würde ich dies nicht empfehlen. – dymanoid