2015-02-25 3 views
5

Ich habe ein Benutzersteuerelement mit einer Schaltfläche und einer Abhängigkeitseigenschaft für die Aktion, die die Schaltfläche ausführen soll. Die Seite, die das Steuerelement enthält, legt die Aktion in XAML fest.Eine Aktion an eine Eigenschaft eines UserControls in XAML binden

MyUserControl.cs

A-Knopf und Abhängigkeitseigenschaft ButtonAction vom Typ Action. Wenn die Schaltfläche angeklickt wird, wird die ButtonAction ausgeführt.

MainPage.xaml.cs

Aktion Action1

Aktion Action2

MainPage.xaml

Präsens eine Instanz von MyUserControl, mit ButtonAction = Action1

Das Problem: Die ButtonAction Eigenschaft wird nicht von dem XAML zugewiesen

MyUserControl.cs

public sealed partial class MyUserControl : UserControl 
{ 

    public Action ButtonAction { 
     get { return (Action)GetValue(ButtonActionProperty); } 
     set { SetValue(ButtonActionProperty, value); } 
    } 

    public static readonly DependencyProperty ButtonActionProperty = 
     DependencyProperty.Register("ButtonAction", typeof(Action), typeof(MyUserControl), new PropertyMetadata(null,ButtonAction_PropertyChanged)); 

    private static void ButtonAction_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { 
     Debug.WriteLine("ButtonAction_PropertyChanged"); 
     // Is not called! 
    } 


    public MyUserControl() { 
     this.InitializeComponent(); 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) { 
     if (ButtonAction != null) { 
      // Never reaches here! 
      ButtonAction(); 
     } 
    } 
} 

MyUserControl.xaml

<Grid> 
    <Button Click="Button_Click">Do The Attached Action!</Button> 

</Grid> 

MainPage.xaml.cs

Action Action1 = (
     () => { Debug.WriteLine("Action1 called"); }); 

    Action Action2 = (() => { Debug.WriteLine("Action2 called"); }); 

MainPage.xaml

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <local:MyUserControl x:Name="myUserControl" ButtonAction="{Binding Action1}"/> 
</Grid> 

Es tut Arbeit, wenn in der Code-Behind für Mainpage (MainPage.xaml.cs) ich die Aktion in dem Loaded Ereignisse zuordnen.

 private void Page_Loaded(object sender, RoutedEventArgs e) { 
     this.myUserControl.ButtonAction = Action1; 
    } 

In diesem Fall wird auch der PropertyChanged-Callback im Benutzersteuerelement aufgerufen. (Dieser Handler wird nur für Diagnosezwecke zur Verfügung gestellt. Ich kann nicht sehen, wie er verwendet werden kann, um die Eigenschaft in der Praxis zu unterstützen).

+0

Was ist der DataContext von der MainPage? Wenn es nicht die Seite ist, dann müssen Sie ButtonAction setzen = "{Binding Action1, ElementName = x: Name der MainPage}" – Dani

+0

Die MainPage hat keinen Datenkontext - aber es funktioniert gut, wenn die Aktion im Code zugewiesen ist- hinter. Ich habe deinen Vorschlag ausprobiert (setze den Namen der Seite und ElementName) und es machte keinen Unterschied. Danke trotzdem. –

Antwort

4

Das Problem liegt in Ihrer Datenbindung. Die Action1 in ButtonAction="{Binding Action1}" sollte eine öffentliche Eigenschaft sein, während Sie es als eine private Variable definiert.

Sie können auch nicht einfach eine normale Eigenschaft direkt im Code dahinter deklarieren. Sie benötigen entweder eine Abhängigkeitseigenschaft oder häufiger eine öffentliche Eigenschaft innerhalb eines Viewmodels, das INotifyPropertyChanged implementiert.

Wenn wir mit dem zweiten Ansatz gehen, müssen wir eine ViewModel Klasse wie folgt mit einer Action1 Eigenschaft erstellen. Beachten Sie die OnPropertyChanged Zeug ist nur die Standard-Art der Umsetzung INotifyPropertyChanged.

public class ViewModel : INotifyPropertyChanged 
{ 
    private Action _action1; 
    public Action Action1 
    { 
     get { return _action1; } 
     set 
     { 
      _action1 = value; 
      OnPropertyChanged("Action1"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string name) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
} 

Und dann brauchen Sie nur das mit dem DataContext Ihrer Haupt-Seite zuzuordnen.

public MainPage() 
    { 
     this.InitializeComponent(); 

     var vm = new ViewModel(); 
     vm.Action1 = (() => 
     { 
      Debug.WriteLine("Action1 called"); 
     }); 

     this.DataContext = vm; 
    } 

Mit diesen beiden Änderungen, Ihr ButtonAction Rückruf jetzt feuern sollte. :)

+0

Beide Lösungen bestätigt zu arbeiten. Sehr interessant, dass sowohl INotifyPropertyChanged als auch DependencyObject für die Datenbindung in xaml gleichwertig funktionieren. –

+0

Das scheint für WinRT-Programmierer allgemein bekannt zu sein, und ich denke, ich wusste es bereits, aber diese Frage war mit einem Bonus für etwa 5 Tage unbeantwortet. Ich schlage vor, dass das Problem darin besteht, dass wir, während wir diese Dinge in der Praxis anwenden, wirklich nicht verstehen, besonders wenn es um den XAML geht. –

+1

Der Code für die Abhängigkeitsobjekt-Lösung lautet: 'class ViewModel: DependencyObject {öffentliche Aktion Action1 {get {return (Action) GetValue (Action1Property); } set {SetValue (Action1Property, Wert); }} public static schreibgeschützt DependencyProperty Action1Property = DependencyProperty.Register ("Action1", typeof (Aktion), typeof (ViewModel), neues PropertyMetadata (null)); } ' –