首页 > 解决方案 > ItemsControl ItemTemplate Binding 选择了错误的视图模型

问题描述

我重写了这个问题:

使用 WPF 和 caliburn micro,当调用 Select 时,我与“Select”方法的绑定选择了错误的视图模型(“this”是错误的)

interface Base
{
    void Select();
    // and more, eg IsSelected, ButtonName
}

class ViewModel : Base
{
    List<Base> Items;
    void Select()
    {
        // now this=A which is wrong
    }
}

void Run()
{
    var A = new ViewModel();
    var B = new ViewModel();
    A.Items.Add(B);
}

视图包含以下内容:

            <ItemsControl ItemsSource="{Binding Items}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <RadioButton Style="{StaticResource RadioButtonSelectorStyle}" GroupName="Main" Content="{Binding ButtonName}" IsChecked="{Binding IsSelected}">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="Click">
                                    <cal:ActionMessage MethodName="Select" />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </RadioButton>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>

标签: c#wpfcaliburn.micro

解决方案


如果您有混合或复合集合,在DataTemplate通过设置定义没有类型提示的情况下DataType,XAML 解析器必须推断实际数据类型。现在,如果引用的(虚拟)成员在公共基类或接口中定义,则解析器假定随机匹配实现来解析引用。

如果您绑定到属性,则此行为没有副作用,除非它们被定义为virtual(很少见,因为属性不是用来实现行为,而是用来存储状态)。但是由于您绑定到一个方法,当每个实现或专门化提供其自己的引用方法的实现时,您会遇到意外的行为。

解决方案是显式定义DataTypeDataTemplate尤其是在处理复合集合时。
为了动态模板化数据,您必须DataTemplate为每个项目类型定义一个。您可以在egResourceDictionary范围内的a 中定义它们。由于模板是隐式的(没有键),它们将自动应用于当前数据类型:ItemsControlItemsControl.Resources

<ItemsControl>
  <ItemsControl.Resources>
    <DataTemplate DataType="{x:Type RadioButtonViewModel}>
      <RadioButton>
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="Click">
            <cal:ActionMessage MethodName="Select" />
          </i:EventTrigger>
        </i:Interaction.Triggers>
      </RadioButton>
    </DataTemplate>

    <DataTemplate DataType="{x:Type ScreenViewModel}>
      <RadioButton>
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="Click">
            <cal:ActionMessage MethodName="Select" />
          </i:EventTrigger>
        </i:Interaction.Triggers>
      </RadioButton>
    </DataTemplate>
  </ItemsControl.Resources>
</ItemsControl>

推荐阅读