Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

inject Action into UserControl

My View Contains a Button and a UserControl. The UserControl also contains a Button. Both, Button1 in my View and Button2 in my UserControl should call the same method in the ViewModel.

ViewViewModelUserControl

Therefore I need to 'inject' (don't know how to call it) the RelayCommand into the UserControl. I thought it would be easy with dependency properties but i can't get it to work.

What i tried:

The UserControl contains a dependency property which is set in the XAML Code of the View containing the UserControl:

UserControl Code:

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());

View Xaml Code: (usage of the dp in the UserControl)

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

The LoadDataCommand from the UserControl is bound to this property in the 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);
    }
}

The ActionTest property is initialized in the Constructor of the ViewModel

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

The visual studio output window also gave me a binding error (which i don't understand)

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')

I found a workaround which is working but i don't like it. I set the LoadDataCommand in LoadedEvent of View codebehind. It looks messy to me and i feel i missed some important concepts.

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

Questions:

  • How do i pass a Command/Action defined in the ViewModel into a UserControl using xaml code in the View?
  • Why is my current approach with bindings not working?
  • Am I missing some fundamental concepts? (Could i archieve this easier with delegates? (I tried..))
like image 855
Joel Avatar asked Mar 21 '23 20:03

Joel


1 Answers

As evident from the error:

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

binding engine is searching for property in control and not in your ViewModel. (by default it searches for property in DataContext of control and i suspect you have set DataContext of control to itself somewhere in your code)

Use RelativeSource to get DataContext of your UserControl which will be your ViewModel.

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

Also instead of creating DP of type Action, use ICommand and create ICommand in your ViewModel and bind to it.

like image 50
Rohit Vats Avatar answered Apr 01 '23 01:04

Rohit Vats