1

I've been using MVVM's RelayCommand with success to bind actions to XAML, but I'm having a small problem with my ItemsControl.

    <ItemsControl ItemsSource="{Binding Devices}" >
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid Width="100" Margin="4" >
                    <Button Command="{Binding Path=SelectDeviceCommand}" >
                        <Grid>
                            <Image Source="img_small.png"></Image>
                            <Image Source="{Binding Path=Logo}" />
                        </Grid>
                    </Button>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

In my view model:

    public RelayCommand SelectDeviceCommand { get; set; }
    private ObservableCollection<Device> Devices;

    Devices = CreateListOfDevices();

    private void InitializeCommands()
    {
        SelectDeviceCommand = new RelayCommand((s) => MessageBox.Show(s.ToString()));
    }

How do I define my SelectDeviceCommand in my view model in order to receive object that is bound to that item?

My SelectDeviceCommand is not even being called... (but that I guess is because I need to make my Device a mini-viewmodel and implement the SelectDeviceCommand in it, is that correct?)

Padu Merloti
  • 3,219
  • 3
  • 33
  • 44

3 Answers3

4

If you use a ViewModelLocator like in MVVM Light applications, you can get a reference to the MainViewModel from within the DataTemplate with

<Button Command="{Binding Main.SelectDeviceCommand, Source={StaticResource Locator}}">

I find this way cleaner than the ElementName one, but of course it supposes that the Main property is available in the locator, and also that the MainviewModel is instantiated as a singleton. This is not always possible, obviously. In that case, I consider the ElementName workaround acceptable.

In WPF, you can also use a RelativeSource with Mode=FindAncestor, but I find it even messier ;)

Regarding the question "How do I define my SelectDeviceCommand in my view model in order to receive object that is bound to that item?", I am not 100% sure that I understand the question, but if you want to get the item (in this case a Device) that is represented by the DataTemplate, you should use the CommandParameter:

<Button Command="{Binding Main.SelectDeviceCommand, Source={StaticResource Locator}}"
        CommandParameter="{Binding}"}">

Cheers, Laurent

LBugnion
  • 6,672
  • 2
  • 24
  • 28
0

Yeah, I've struck this one. I've seen some people work around it with a custom "CommandReference" class that they add as a resource to the window, but I couldn't get that to work.

In the end, I used element binding back to the window (or page) itself, since the ViewModel is the DataContext of the window. First, give your window (or page) a name:

<Window ...
    x:Name="me" />

Then bind to the window's datacontext directly, like this:

<Button Command="{Binding DataContext.SelectDeviceCommand,ElementName=me}">

This has worked for me. It's messy, but I think it's pretty readable.

Matt Hamilton
  • 200,371
  • 61
  • 386
  • 320
0

I have a usercontrol(x:Name="ControlClass") and it is inside a template, it doesnt work on xaml i called it like this

<Button Content="New1" Command="{Binding DataContext.NewTabCommand,ElementName=ControlClass}"/>



namespace Doit_Project.Modules.Tasks.ViewModels
{
    [Export]
    public class WindoTabViewModel : Doit_ProjectViewModelBase
    {
        public WindoTabViewModel()
        {

        }

        private RelayCommand _newTabCommand;
        public RelayCommand NewTabCommand
        {
            get { return _newTabCommand ?? (_newTabCommand = new RelayCommand(OnNewTab)); }
        }

        public void OnNewTab()
        {

        }
    }
}
robert
  • 33,242
  • 8
  • 53
  • 74
John
  • 1