2009-05-27 17 views
1

ich WPF bin mit Visual Studio 2008 habe ich eine einfache WPF Usercontrol mit dem folgenden Code habe:Aktualisieren WPF Usercontrol über XAML

public partial class UserControl1 : UserControl 
    { 
    public UserControl1() 
    { 
     InitializeComponent(); 
     Composite = new Composite(); 
    } 

    protected override void OnRender(DrawingContext drawingContext) 
    { 
     //LayoutRoot is name of default Grid instance 
     if (!LayoutRoot.Children.Contains(Composite)) 
     { 
     LayoutRoot.Children.Add(Composite); 
     } 
    } 

    public Composite Composite 
    { 
     get; 
     set; 
    } 
    } 

    public class Composite : ContentControl 
    { 
    protected override void OnRender(DrawingContext drawingContext) 
    { 
     drawingContext.DrawRectangle(new SolidColorBrush(Color), new Pen(Brushes.Black, 1.0), new Rect(RenderSize)); 
    } 

    public Color Color 
    { 
     get; 
     set; 
    } 
    } 

ich dann dieses Benutzersteuerelement in einer WPF-Anwendung verwenden, die XAML der Seite suchen wie folgt aus:

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:test="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1" 
    Title="Window1" Height="500" Width="700" Background="AliceBlue"> 
    <test:UserControl1 Name="uControl1"> 
    <test:UserControl1.Composite> 
     <test:Composite Color="Green"/> 
    </test:UserControl1.Composite> 
    </test:UserControl1> 
</Window> 

Meine Frage ist: was Code kann ich auf die oben hinzuzufügen, so dass durch „Composite-Farbe“ auf etwas anderes als Grün zu ändern und die Return-Taste schlagen, das Usercontrol automatisch aktualisiert? Das Verhalten, nach dem ich suche, ist, was passiert, wenn Sie den Hintergrund von Window1 auf eine andere Farbe als AliceBlue ändern und zurück drücken.

Wenn ich den Code die richtige Farbe zeigt, ist das Problem mit der Aktualisierung zur Designzeit über XAML.

Vielen Dank für Hinweise, die mir helfen zu verstehen, was hier vor sich geht!

Antwort

9

WPF ist so optimiert, dass Elemente nur dann erneut gezeichnet werden, wenn dies unbedingt erforderlich ist. Das Verhalten ist daher teilweise darauf zurückzuführen, dass WPF nicht weiß, dass das Steuerelement beim Ändern von Composite.Color neu gezeichnet werden muss.

Darüber hinaus wird der Visual Studio/Blend-Designer (oder XAML-Steuerelemente) nicht bemerken, dass diese Eigenschaft geändert hat, da Ihr Steuerelement nicht signalisiert, dass diese Eigenschaft geändert wird; Ohne diese Benachrichtigung wüsste WPF nicht, dass die Eigenschaft geändert wurde (was es davor bewahrt, die gesamte Zeit zu überprüfen, um zu sehen, ob sich die Dinge geändert haben).

Während Sie INotifyPropertyChanged implementieren und das zweite Problem beheben können, da Sie von ContentControl erben (das in der Vererbungshierarchie INotifyPropertyChanged implementiert), können Sie eine DependencyProperty verwenden und beide Probleme beheben - und WPF verbessern verbindliche Unterstützung, um zu booten!

// DependencyProperty backing store for Color. This enables animation, styling, binding, etc... 
public static readonly DependencyProperty ColorProperty = 
    DependencyProperty.Register("Color", typeof(Color), typeof(Composite), 
    new FrameworkPropertyMetadata(new Color(), FrameworkPropertyMetadataOptions.AffectsRender)); 

public Color Color 
{ 
    get { return (Color)GetValue(ColorProperty); } 
    set { SetValue(ColorProperty, value); } 
} 

Durch die Einstellung FrameworkPropertyMetadataOptions.AffectsRender, weiß, WPF, dass, wenn diese Eigenschaft geändert wird, Verfahren der Renderpass für diesen Artikel werden muss erneut durchgeführt und wird erneut rendern Ihre Kontrolle, Ihre OnRender() aufrufen und die neue Farbe anzeigen. Und als DependencyProperty generiert es automatisch das richtige PropertyChanged-Ereignis, sodass jeder, der Ihre Klasse beobachtet (wie das Bindungs- und Animationssystem von WPF), benachrichtigt wird, sobald sich die Eigenschaft ändert.

+0

Dank Nicholas, aber dieser Code erzeugt einen System.Windows.Markup.XamlParseException Fehler, wenn auf mein Codebeispiel angewendet. Wenn ich den FrameworkPropertyMetadataOptions.AffectsRender-Parameter aus dem FrameworkPropertyMetadata-Konstruktor entferne, erhalte ich den Fehler nicht, aber mein Problem ist nicht gelöst. –

+0

Das ist, was ich bekomme, um meinen Code nicht vollständig zu testen! Ich habe den Code aktualisiert und getestet, dass er funktioniert. Ich habe die DependencyProperty versehentlich auf null initialisiert, was mit einer XamlParseException fehlschlägt. Indem Sie den Wert mithilfe der neuen Farbe() auf Weiß initialisieren, wird DependencyProperty initialisiert und der Designer aktualisiert, sobald Sie die Farbe ändern. Entschuldigen Sie. –

+0

Das funktioniert jetzt, danke Nicholas! Das Festlegen des defaultValue-Parameters auf null scheint nur dann ein Problem zu sein, wenn Sie einen flags-Parameter definieren, andernfalls funktioniert null einwandfrei. Wie auch immer, ich kann jetzt deine Antwort als Antwort markieren. Danke noch einmal! –

0

Sie gehen auf eine sehr seltsame Art und Weise vor (erinnert an eine MFC-Steuerung); Nimm dir etwas Zeit und lese die erste Hälfte von WPF Unleashed durch (http://www.amazon.com/Windows-Presentation-Foundation-Unleashed-WPF/dp/0672328917/ref=sr_1_1?ie=UTF8&s=books&qid=1243491021&sr=8-1), es macht Spaß zu lesen und alles macht viel mehr Sinn für.

+0

Danke für den Tipp, Paul.Das Steuerelement, an dem ich arbeite, verwendet große Datasets, die in der Regel zu groß sind, um zur Entwurfszeit in XAML einzugeben. Dies bedeutet, dass ich zur Laufzeit eine große Anzahl von Objekten dynamisch erstellen muss, was per MFC mit WPF problemlos möglich ist. Ich möchte jedoch auch einige weitere WPF-Vorteile für dieses Modell vorstellen, daher erben wir diese Objekte von ContentControl und lassen jedes Objekt selbst rendern, anstatt den DrawingContext von einem zum anderen zu übertragen. –