3
votes

I'm new to WPF and I'm trying to dynamically add a Button inside a ContentControl, which should fire a command when clicked. I'm using MVVMLight to handle the Commands.

Below I have an example with two buttons. The top button is placed directly into the StackPanel. This button fires off the Command as expected.

The second button is placed inside a ContentControl. It displays correctly, but the Command does not fire when the button is clicked. I assumed this is because the Binding does not transfer down through the DataTemplate, but it seems to work if I use regular Commands instead of MVVMLight RelayCommands.

I don't want to remove the framework, so I'm wondering if anyone knows how to fix it? Thanks

<Window x:Class="ContentControlExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:ContentControlExample.ViewModel">

    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>

    <Window.Resources>
        <DataTemplate x:Key="MyButton" >
            <Button Content="SUBMIT" Command="{Binding MyCommand}" Width="200" Height="50"/>
        </DataTemplate>
    </Window.Resources>

    <StackPanel>

        <!--When this button is clicked, the Command executes as expected-->
        <Button Content="SUBMIT" Command="{Binding MyCommand}" Width="200" Height="50"/>


        <!--Nothing happens when this button is clicked-->
        <ContentControl ContentTemplate="{StaticResource MyButton}"/>
    </StackPanel>
</Window>

Here's the ViewModel with the command:

public class MainViewModel : ViewModelBase
{
        public ICommand MyCommand { get; private set; }

        public MainViewModel()
        {
            MyCommand = new RelayCommand(MyCommand_Executed, MyCommand_CanExecute);
        }

        private bool MyCommand_CanExecute()
        {
            return true;
        }

        private void MyCommand_Executed()
        {
            MessageBox.Show("The command executed");
        }
    }
2
A proxy for binding may help. See stackoverflow.com/questions/7711275/…dytori

2 Answers

1
votes

The problem here is the implicit DataContext in ContentTemplate is the Content and this has not been set to anything. You need to set Content to some Binding to bridge the DataContext currently in the visual tree, something like this:

<ContentControl ContentTemplate="{StaticResource MyButton}" Content="{Binding}"/>
1
votes

Another solution is to give your Window a name:

<Window x:Class="ContentControlExample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:ContentControlExample.ViewModel"
    x:Name="_this">

Then bind via its context instead:

<Button Content="SUBMIT" Command="{Binding ElementName=_this, Path=DataContext.MyCommand}" Width="200" Height="50"/>

This is particularly handy for things like ListViews and ItemControls, as their DCs get set to the list elements. Keep in mind though that this will only work on members within the same visual tree, if that's not the case (e.g. popup menus etc) then you need to proxy a binding as described in this article.