2014-01-22 6 views
5

My View Содержит Button и UserControl. UserControl также содержит Button. Оба, Button1 в моем представлении и Button2 в моем UserControl должны вызвать тот же метод в ViewModel.вводят действие в UserControl

ViewViewModelUserControl

Поэтому мне нужно «впрыснуть» (не знаю, как назвать это) в RelayCommand в UserControl. Я думал, что будет легко с зависимыми свойствами, но я не могу заставить его работать.

Что я пробовал:

UserControl содержит свойство зависимостей, которое установлено в XAML кодекса, содержащее UserControl:

UserControl Код:

public const string LoadDataCommandPropertyName = "LoadDataCommand"; 
public Action LoadDataCommand 
{ 
    get 
    { 
     return (Action)GetValue(LoadDataCommandProperty); 
    } 
    set 
    { 
     SetValue(LoadDataCommandProperty, value); 
    } 
} 

public static readonly DependencyProperty LoadDataCommandProperty = DependencyProperty.Register(
    LoadDataCommandPropertyName, 
    typeof(Action), 
    typeof(GridViewPersistenceController), 
    new UIPropertyMetadata()); 

Просмотр Xaml Код: (использование dp в UserControl)

<customControls:MyUserControl Grid.Column="1" 
           x:Name="RadGridViewSettingsPersistenceControl" 
           GridControl="{Binding ElementName=RadGridView}" 
           LoadDataCommand="{Binding ActionTest}" 
           /> 

LoadDataCommand от UserControl обязан это свойство в ViewModel

private const string ActionTestPropertyName = "ActionTest"; 
private Action actionTest; 
public Action ActionTest 
{ 
    get 
    { 
     return this.actionTest; 
    } 

    set 
    { 
     this.RaisePropertyChanging(ActionTestPropertyName); 
     this.actionTest = value; 
     this.RaisePropertyChanged(ActionTestPropertyName); 
    } 
} 

ActionTest свойство инициализируется в конструкторе ViewModel

public MyViewModel() 
     { 
      this.ActionTest = new Action(this.LoadData); 
     } 

Окно вывода студии визуального также дало мне связывание ошибка (что я не понимаю)

System.Windows.Data Error: 40 : BindingExpression path error: 'ActionTest' property not found on 'object' ''MyUserControl' (Name='RadGridViewSettingsPersistenceControl')'. BindingExpression:Path=ActionTest; DataItem='MyUserControl' (Name='RadGridViewSettingsPersistenceControl'); target element is 'MyUserControl' (Name='RadGridViewSettingsPersistenceControl'); target property is 'LoadDataCommand' (type 'Action')

Я нашел обходное решение, которое работает, но мне оно не нравится. Я устанавливаю LoadDataCommand в LoadedEvent of View codebehind. Это выглядит беспорядочно для меня, и я чувствую, что пропустил некоторые важные понятия.

//TODO: Dirty coding, fix me 
    private void MyView_OnLoaded(object sender, RoutedEventArgs e) 
    { 
     this.RadGridViewSettingsPersistenceControl.LoadDataCommand = new Action((this.DataContext as MyViewModel).LoadData); 
    } 

Вопросы:

  • Как я прохожу Command/Action определены в ViewModel в UserControl с использованием кода XAML в представлении?
  • Почему мой текущий подход с привязками не работает?
  • Я пропустил некоторые фундаментальные понятия? (Может я это легче АРХИВ с делегатами (я пробовал ..)?)

ответ

5

Как видно из ошибки:

'ActionTest' property not found on 'object' ''MyUserControl' (Name='RadGridViewSettingsPersistenceControl')'

механизм связывания ищет собственности в управлении, а не в вашей ViewModel , (По умолчанию он ищет собственности в DataContext контроля и я подозреваю, что вы установили DataContext управления для себя где-то в вашем коде)

Использование RelativeSource получить DataContext вашего UserControl который будет вашим ViewModel.

LoadDataCommand="{Binding DataContext.ActionTest, 
        RelativeSource={RelativeSource Mode=FindAncestor, 
              AncestorType=UserControl}}" 

Кроме того, вместо создания DP типа Action используйте ICommand и создать ICommand в вашей ViewModel и привязать к нему.

+0

Спасибо, это работает. Почему я должен предпочесть реализации ICommand (например, RelayCommand) над Action? – Joel

+0

Предположим, вы хотите отключить свою кнопку при каком-либо условии. С помощью 'ICommand' вы можете просто написать свой код проверки в команде« CanExecute », но с помощью« Action »вы должны написать дополнительную логику. –

+1

Сэр, вы заработали себе зеленый галочку. – Joel

2

В качестве альтернативы вы можете использовать зависимое свойство . Ниже приведен пример:

AttachedDependencyProperty

public static class UserControlExtension 
{ 
    public static readonly DependencyProperty ActionProperty; 

    public static void SetAction(DependencyObject DepObject, ICommand value) 
    { 
     DepObject.SetValue(ActionProperty, value); 
    } 

    public static ICommand GetAction(DependencyObject DepObject) 
    { 
     return (ICommand)DepObject.GetValue(ActionProperty); 
    } 

    static UserControlExtension() 
    { 
     ActionProperty = DependencyProperty.RegisterAttached("Action", 
                  typeof(ICommand), 
                  typeof(UserControlExtension)); 
    } 
} 

TestViewModel

public class TestViewModel 
{ 
    private ICommand _testButtonCommand = null; 

    public ICommand TestButtonCommand 
    { 
     get 
     { 
      if (_testButtonCommand == null) 
      { 
       _testButtonCommand = new RelayCommand(param => this.TestButton(), null); 
      } 

      return _testButtonCommand; 
     } 
    } 

    private void TestButton() 
    { 
     MessageBox.Show("Test command execute"); 
    } 
} 

MainWindow в View

<Window.Resources> 
    <local:TestViewModel x:Key="TestVM" /> 
</Window.Resources> 

<Grid DataContext="{StaticResource TestVM}"> 
    <local:TestUserControl x:Name="TestUserControl" 
          AttachedProperties:UserControlExtension.Action="{Binding TestButtonCommand}" /> 
</Grid> 

UserControl

<Grid> 
    <Button Name="TestButton" 
      HorizontalAlignment="Center" 
      VerticalAlignment="Center" 
      Content="TestContent" 
      Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, 
           Path=(AttachedProperties:UserControlExtension.Action)}" />   
</Grid> 

Образец проекта доступен here.

+0

AttachedProperties являются для меня совершенно новыми, спасибо за обмен. В этом случае я предпочитаю решение от @Rohit Vats, но я буду учитывать AttachedProperties. Я уверен, что они когда-нибудь станут полезными. – Joel

+1

@Joel: Я поделился вашим образцовым проектом, надеюсь, он вам будет полезен. –

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