I'm showing a list of Orders, (each Order is a UserControl), in more than one Page. Every time the user left-click the control, main window should load & show the order in a new Page using an ICommand.
x:Name of MainWindow is: mainWindow
MainViewModel
This is de view model associated to the MainWindow.
public class MainViewModel : BaseViewModel
{
public INavigator Navigator { get; set; }
public ICommand OpenOrderCommand { get; set; }
public MainViewModel(INavigator navigator) : base()
{
Navigator = navigator;
OpenOrderCommand = new RelayCommand(OpenOrder);
}
private void OpenOrder(object obj)
{
// Loads the order from db
}
}
I've added an InputBindings tag in the UserControl to detect when the user left-click it.
UserControl
<Grid.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding DataContext.OpenOrderCommand,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
CommandParameter="{Binding OrderId}"/>
</Grid.InputBindings>
But OpenOrderCommand
is never fired, and I get a XAML binding failure with this text:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=DataContext.OpenOrderCommand; DataItem=null; target element is 'MouseBinding' (HashCode=20815867); target property is 'Command' (type 'ICommand')
How can I execute a ICommand of MainWindow from a UserControl?
CodePudding user response:
Make sure the UserControl and the Window reside in the same element tree. In case there is a tree boundary, e.g. a Frame, the RelativeSource lookup will fail.
Besides that, your control should expose its own ICommand property (like a Button). It would thus not be dependant on the view model of its parent Window.
Add an ICommand
dependency property
public static readonly DependencyProperty MyCommandProperty =
DependencyProperty.Register(
nameof(MyCommand), typeof(ICommand), typeof(MyUserControl));
public ICommand MyCommand
{
get { return (ICommand)GetValue(MyCommandProperty); }
set { SetValue(MyCommandProperty, value); }
}
and bind to it in the UserControl's XAML
<Grid.InputBindings>
<MouseBinding
MouseAction="LeftClick"
Command="{Binding MyCommand,
RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding OrderId}"/>
</Grid.InputBindings>
When you use the control, write
<local:MyUserControl MyCommand="{Binding OpenOrderCommand}"/>
CodePudding user response:
In the error message it says it can't find the binding source. Try to bind it like this:
<Grid.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding OpenOrderCommand}"
CommandParameter="{Binding OrderId}"/>
</Grid.InputBindings>
and to set the DataContext like this:
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
In my test code the Grid only raised the event when I had explecitly set a value for the Background-Property. Transparent was also a value which worked.