2010-05-18 16 views
9

Ich habe eine Klasse namens MyComponent und es hat eine DependencyProperty caled BackgroundProperty.WPF benutzerdefinierte DependencyProperty Benachrichtigen Änderungen

MyBackground ist eine Klasse, die von DependencyObject abgeleitet ist und einige DependencyProperties aufweist.

public class MyBackground : DependencyObject 
{ 
    public Color BaseColor 
    { 
     set { SetValue(BaseColorProperty, value); } 
     get { return (Color)GetValue(BaseColorProperty); } 
    } 
    public static readonly DependencyProperty BaseColorProperty = 
     DependencyProperty.Register("BaseColor", typeof(Color), 
      typeof(MyBackground), new UIPropertyMetadata(Colors.White)); 

    [...] 
} 

Nun, was ich will, ist, wenn eine Eigenschaft von MyBackground geändert wird, benachrichtigt werden MyComponent dass MyBackground geändert hat und der PropertyChangedCallback OnPropertyChanged Namen genannt werden.

+0

Ich bin irgendwie verwirrt, warum brauchen Sie das. Normalerweise ist es umgekehrt, wenn DP für Bindungen verwendet werden und wenn diese sich ändern, möchten Sie die DP informieren. Warum würdest du es anders herum brauchen? –

+0

Was meinst du damit rückwärts @Omribitan? Dies ist Standard-WPF. Wenn ich den Wert einer Abhängigkeitseigenschaft ändere, wissen alle an diese Eigenschaft gebundenen Dinge sofort darüber. Dies ist eine Art von Abhängigkeitseigenschaften - und die Datenbindung von WPF basiert auf diesem Konzept. – BrainSlugs83

+0

@ BrainSlugs83 Denken Sie an die Sichtbarkeit eines Steuerelements, das an eine Eigenschaft der ViewModel-Klasse gebunden ist, nennen wir es 'IsVisibile'. Die Sichtbarkeit ist die DP und die IsVisibile ist eine einfache Eigenschaft. Was normalerweise passiert, ist, wenn 'IsVisible' ändert, dass Sie die Benutzeroberfläche benachrichtigen wollen (meistens mit' INotifyPropertyChanged'), damit die 'DP' ihren Wert ändert, nicht umgekehrt ... –

Antwort

3

Bär mit mir für eine Sekunde, weil es scheint, dass Sie gegen das Korn von WPF zu gehen versuchen. Da es so aussieht, als würden Sie Code schreiben, der mit der Anzeigelogik in Beziehung steht, ist die typische Methode, um DependencyObject s miteinander zu interagieren, Bindungen.

Wenn zum Beispiel ist MyComponent eine Kontrolle irgendeiner Art und verwendet die Background Eigenschaft in seinem ControlTemplate, würden Sie ein TemplateBinding verwenden, die das Background Eigentum und alle wichtigen Untereigenschaften verweisen.

Da 1) Sie wahrscheinlich bereits wissen, und 2) Sie entweder keine Vorlagen verwenden oder sie nicht verfügbar haben, können Sie eine Bindung in Code einrichten, um auf Änderungen in der Background Eigenschaft zu reagieren. Wenn Sie weitere Einzelheiten über Ihre Methode angeben, kann ich Ihnen Beispielcode zur Verfügung stellen.

3

Eine Möglichkeit zu tun, was Sie beschreiben, wäre von Freezable anstelle von DependencyObject abzuleiten. Wenn eine Eigenschaft von Freezable den PropertyChangedCallback für alle DO-Verweise ändert, die Freezable aufrufen, wird der Rückruf für die Hintergrundeigenschaft von MyComponent aufgerufen. In diesem Fall sind e.OldValue und e.NewValue die gleiche Referenz. Intern weist WPF eine Markierung für die Ereignisargumente auf, die angibt, dass es sich um eine Unterobjektänderung handelt.

Dies ist, was das Framework für Dinge wie Pinsel tut, so dass ein Element ungültig gemacht werden kann, wenn beispielsweise die Color-Eigenschaft eines SolidColorBrush geändert wird. Wenn ein Objekt nie geändert wird (oder wenn Sie es threadsicher machen wollen), kann man das Objekt einfrieren (d. H. Es unveränderlich machen).

BTW Ich würde wahrscheinlich vermeiden, Hintergrund als Name der Eigenschaft zu verwenden. Die meisten Entwickler gehen davon aus, dass der Typ Brush das ist, was das Framework für diese benannte Eigenschaft an mehreren seiner Elemente verwendet (z. B. Steuerung, Rahmen).

0

Hier ist eine kleine statische Klasse von Erweiterungsmethoden, die ich für WPF geschrieben habe - es ermöglicht Ihnen, einen EventHandler oder einen Aktionsrückruf für das Ändern von DependencyProperty auf jedem DependencyObject zu registrieren. Änderungen am Abhängigkeitsobjekt sind nicht notwendig.

Es verhindert auch Rekursion (das heißt, wenn Sie die gleiche Eigenschaft während des Rückrufs ändern, etc ..)

Es nutzt die DependencyPropertyDescriptor dass @ScottBilas verknüpft.

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Text; 
using System.Windows; 

namespace BrainSlugs83.Writes.Too.Much.Code 
{ 
    public static class WpfExtensions 
    { 
     public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, Action<T> callback) where T : DependencyObject 
     { 
      if (callback != null) 
      { 
       obj.OnPropertyChanged(prop, new EventHandler((o, e) => 
       { 
        callback((T)o); 
       })); 
      } 
     } 

     public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, EventHandler handler) where T : DependencyObject 
     { 
      var descriptor = DependencyPropertyDescriptor.FromProperty(prop, typeof(T)); 
      descriptor.AddValueChanged(obj, new EventHandler((o, e) => 
      { 
       if (handler != null) 
       { 
        if (o == null) { handler(o, e); } 
        else 
        { 
         lock (PreventRecursions) 
         { 
          if (IsRecursing(obj, prop)) { return; } 
          SetIsRecursing(obj, prop, true); 
         } 

         try 
         { 
          handler(o, e); 
         } 
         finally 
         { 
          SetIsRecursing(obj, prop, false); 
         } 
        } 
       } 
      })); 
     } 

     #region OnPropertyChanged Recursion Prevention 

     private static readonly Dictionary<object, List<DependencyProperty>> PreventRecursions = new Dictionary<object, List<DependencyProperty>>(); 

     private static bool IsRecursing(object obj, DependencyProperty prop) 
     { 
      lock (PreventRecursions) 
      { 
       List<DependencyProperty> propList = null; 
       if (PreventRecursions.ContainsKey(obj)) 
       { 
        propList = PreventRecursions[obj]; 
       } 

       return propList == null ? false : propList.Contains(prop); 
      } 
     } 

     private static void SetIsRecursing(object obj, DependencyProperty prop, bool value) 
     { 
      lock (PreventRecursions) 
      { 
       List<DependencyProperty> propList = null; 
       if (PreventRecursions.ContainsKey(obj)) 
       { 
        propList = PreventRecursions[obj]; 
       } 

       if (propList == null) 
       { 
        if (!value) { return; } 

        propList = PreventRecursions[obj] = new List<DependencyProperty>(); 
       } 

       if (value) 
       { 
        if (!propList.Contains(prop)) 
        { 
         propList.Add(prop); 
        } 
       } 
       else 
       { 
        while (propList.Contains(prop)) 
        { 
         propList.Remove(prop); 
        } 

        if (!propList.Any()) 
        { 
         propList = PreventRecursions[obj] = null; 
        } 
       } 
      } 
     } 

     #endregion 

     public static bool IsInDesignMode(this DependencyObject obj) 
     { 
      try 
      { 
       return DesignerProperties.GetIsInDesignMode(obj); 
      } 
      catch { /* do nothing */ } 

      return false; 
     } 
    } 
} 
Verwandte Themen