2015-02-25 6 views
5

У меня есть пользовательский элемент управления, у которого есть кнопка и свойство зависимости для действия, которое должна выполнить кнопка. Страница, содержащая элемент управления, устанавливает действие в XAML.Привязать действие к свойству UserControl в XAML

MyUserControl.cs

кнопку, и свойство зависимостей ButtonAction, типа Action. Когда кнопка нажата, она выполняет команду ButtonAction.

MainPage.xaml.cs

Действие Action1

Действие Мотор2

MainPage.xaml

Present экземпляр MyUserControl с ButtonAction = действий1

Проблема: Свойство ButtonAction не назначается из XAML

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> 

Это делает работу, если в коде-позади для MainPage (MainPage.xaml.cs) Поручаю действие в Loaded случае.

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

В этом случае также вызывается обратный вызов PropertyChanged в пользовательском элементе управления. (Этот обработчик предоставляется только для диагностических целей. Я не вижу, как его можно использовать для поддержки свойства на практике).

+0

Что такое DataContext от MainPage? Если это не страница, вам нужно установить ButtonAction = "{Binding Action1, ElementName = x: name MainPage}" – Dani

+0

MainPage не имеет контекста данных, но он отлично работает, когда это действие назначается в коде- за. Я попробовал ваше предложение (задал имя страницы и ElementName), и это не имело никакого значения. Но все равно спасибо. –

ответ

4

Проблема заключается в привязке данных. Action1 в ButtonAction="{Binding Action1}" должно быть общественное имущество, пока вы определили его как частную переменную.

Кроме того, вы не можете просто объявить нормальное свойство непосредственно в коде, подобном этому. Вам понадобится либо имущество , либо, как правило, общественная собственность внутри a viewmodel который реализует INotifyPropertyChanged.

Если мы перейдем ко второму подходу, нам нужно будет создать класс , например, Action1. Обратите внимание, что материал OnPropertyChanged - это стандартный способ реализации 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)); 
     } 
    } 
} 

И тогда вам просто необходимо присвоить это к DataContext вашей главной страницы.

public MainPage() 
    { 
     this.InitializeComponent(); 

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

     this.DataContext = vm; 
    } 

С помощью этих двух изменений, ваш ButtonAction обратного вызова должна быть обжиг. :)

+0

Оба решения подтвердили свою работу. Очень интересно, что и INotifyPropertyChanged, и DependencyObject работают эквивалентно для привязки данных в xaml. –

+0

Это может показаться общим знанием для программистов WinRT, и я думаю, что я уже знал, но этот вопрос был без ответа с бонусом в течение примерно 5 дней. Я полагаю, что проблема в том, что, хотя мы используем эти вещи на практике, мы действительно не понимаем, особенно когда речь заходит о XAML. –

+1

Код для решения объекта-зависимого объекта: 'class ViewModel: DependencyObject {public Action Action1 {get {return (Action) GetValue (Action1Property); } set {SetValue (Action1Property, значение); }} public static readonly DependencyProperty Action1Property = DependencyProperty.Register («Action1», typeof (Action), typeof (ViewModel), новый PropertyMetadata (null)); } ' –

Смежные вопросы