动态创建控件时,RadioButton 上的已检查事件命令绑定不起作用

Checked event command binding on RadioButton doesn't work when the control is dynamically created

我有 3 个 RadioButton 控件,我在我定义的自定义 class 和 ItemsControl 的帮助下动态添加到我的 WPF 程序中。我的习惯 class 很简单;它有两个属性,一个是标识符,另一个是 bool 来表示 Checked/Unchecked 状态。

public class RadioButtonItem
{
    public string ItemName { get; set; }
    public bool IsChecked { get; set; }
}

我正在使用 MVVMLight,并且 ViewModelDataContext 等都已正确设置。

MainWindow 中,我添加了 RadioButton 控件,如下所示:

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

注意 iInteractivity 命名空间: xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

现在在我的 ViewModel 中,我创建了一个 RadioButtonItem 实例的列表,并且在加载时它在 XAML 端创建了 3 个 RadioButton 控件就好了,正如我所料。然后使用 MVVMLight 命令 RelayCommand,我将 Checked 事件连接到 RadioButtonCheckedCommand 命令,后者又应该调用 RadioButtonChecked() 私有方法。

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

    }
}

但是,当我 运行 程序时,它不会调用上述事件。它也没有给我任何错误。如何让事件在这样动态创建的控件中工作?

为了验证我的命令绑定等是否有效,我还在 window 上创建了三个静态 RadioButton 控件,如下所示,并将它们附加到同一个命令,它们在 Checked事件。

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

ItemsControl 中,绑定到 RadioButtonCheckedCommand 正在尝试根据项目解析它 - RadioButtonItem 实例

但是命令是在 MainViewModel 中定义的。它在 StackPanel 中工作,因为没有绑定到 RadioButtonItems。

解决方案是绑定到ItemsControl.DataContext(与Grid.DataContext相同):

<i:InvokeCommandAction Command="{Binding Path=DataContext.RadioButtonCheckedCommand, ElementName=LayoutRoot}"/>

之前的回答很完美。如果您不想使用 elemnt name "LayoutRoot".

,这只是另一种解决方案

<i:InvokeCommandAction Command="{Binding Path=DataContext.RadioButtonCheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"/>