I have 3 RadioButton
controls that I add to my WPF
program dynamically, with the help of a custom class I've defined and an ItemsControl
. My custom class is simple; it has two properties, one an identifier and the other a bool
to represent the Checked/Unchecked
status.
public class RadioButtonItem
{
public string ItemName { get; set; }
public bool IsChecked { get; set; }
}
I'm using MVVMLight
, and a ViewModel
, and DataContext
etc are all properly setup.
In the MainWindow
I have the RadioButton
controls added like so:
<Grid x:Name="LayoutRoot">
<ItemsControl ItemsSource="{Binding Path=RadioButtons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding ItemName}"
IsChecked="{Binding IsChecked}"
Margin="12" GroupName="ABC">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding RadioButtonCheckedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Note that i
is the Interactivity
namespace:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Now in my ViewModel
, I create a list of RadioButtonItem
instances, and at loading time it creates 3 RadioButton
controls in the XAML
end just fine, as I expect it to. Then using MVVMLight
command RelayCommand
, I hook up the Checked
event to the RadioButtonCheckedCommand
command, which in turn is supposed to call the RadioButtonChecked()
private method.
public class MainViewModel : ViewModelBase
{
private List<RadioButtonItem> _radioButtons;
public List<RadioButtonItem> RadioButtons
{
get => _radioButtons;
set { _radioButtons = value; RaisePropertyChanged(); }
}
public RelayCommand RadioButtonCheckedCommand { get; private set; }
public MainViewModel()
{
RadioButtons = new List<RadioButtonItem>
{
new RadioButtonItem() { ItemName = "A", IsChecked = false },
new RadioButtonItem() { ItemName = "B", IsChecked = false },
new RadioButtonItem() { ItemName = "C", IsChecked = false },
};
RadioButtonCheckedCommand = new RelayCommand(RadioButtonChecked);
}
private void RadioButtonChecked()
{
}
}
But, when I run the program it doesn't call the said event. Neither does it give me any errors. How do I get an event to work in a dynamically created control like this?
To verify my command bindings etc. work, I also created three static RadioButton
controls on my window, as shown below, and attached them to the same command and they work fine on Checked
event.
<StackPanel Grid.Row="1" HorizontalAlignment="Center">
<RadioButton Content="X" Margin="12">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding RadioButtonCheckedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</RadioButton>
<RadioButton Content="Y" Margin="12">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding RadioButtonCheckedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</RadioButton>
<RadioButton Content="Z" Margin="12">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding RadioButtonCheckedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</RadioButton>
</StackPanel>
inside ItemsControl
, binding to RadioButtonCheckedCommand is trying to resolve it against an item - RadioButtonItem
instance
but the command is defined in MainViewModel. it works in the StackPanel because there are no bindings to RadioButtonItems.
the solution is to bind to ItemsControl.DataContext (same as Grid.DataContext):
<i:InvokeCommandAction Command="{Binding Path=DataContext.RadioButtonCheckedCommand, ElementName=LayoutRoot}"/>