【问题标题】:XAML Binding Failures on ComboBoxComboBox 上的 XAML 绑定失败
【发布时间】:2021-10-01 15:52:21
【问题描述】:

我创建了一个在 XAML 中添加一个项目的 ComboBox,这样我就可以拥有一个不可编辑的 ComboBox,其中包含一个将绑定项目设置为 null 的选项。

以下代码有效,但 Visual Studio 报告了一些我不知道如何修复的 XAML 绑定失败。

<ComboBox x:Name="NewNewComboBox"
          SelectedValuePath="CompCategoryId"
          DisplayMemberPath="CategoryName">
    <ComboBox.Resources>
        <CollectionViewSource x:Key="MyCollection" Source="{Binding Categories}"/>
    </ComboBox.Resources>
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <ComboBoxItem FontStyle="Italic" FontSize="8px" Content="(clear)" />
            <CollectionContainer Collection="{Binding Source={StaticResource MyCollection}}"  />
        </CompositeCollection>
    </ComboBox.ItemsSource>
    <ComboBox.SelectedValue>
        <Binding Path="CompCategoryId"/>
    </ComboBox.SelectedValue>
</ComboBox>

注意:普通的 ComboBox(没有 (clear) 项)不会显示任何失败。

编辑:我希望解决方案避免特定于 ComboBox 使用的类的代码,因为我想将此 ComboBox 作为 UserControl 以便可以在不同的类(它们都有一个 int Id 和字符串 Name,已经由 SelectedValuePath 和 DisplayMemberPath 定义)

我已修改 ComboBoxItem 并且不再收到 XAML 绑定失败。但我无法编辑它的 FontStyle(而且我不知道如何将其实现为可重用的 UserControl)

<ComboBox x:Name="NewNewComboBox"
          SelectedValuePath="CompCategoryId"
          DisplayMemberPath="CategoryName"
          SelectionChanged="NewNewComboBox_SelectionChanged">
    <ComboBox.Resources>
        <CollectionViewSource x:Key="MyCollection" Source="{Binding Categories}"/>
    </ComboBox.Resources>
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <m:CompCategory CategoryName="(clear)" CompCategoryId="0"/>
            <CollectionContainer Collection="{Binding Source={StaticResource MyCollection}}"  />
        </CompositeCollection>
    </ComboBox.ItemsSource>
    <ComboBox.SelectedValue>
        <Binding Path="CompCategoryId"/>
    </ComboBox.SelectedValue>
</ComboBox>

private void NewNewComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (NewNewComboBox.SelectedIndex == 0) NewNewComboBox.SelectedValue = null;
}

【问题讨论】:

  • 阅读我的答案的补充。

标签: c# wpf xaml


【解决方案1】:

您指定绑定到 Categories 集合的元素(类型 Category?)的属性。
但是您的 CombobBox 未绑定到 Categories 集合,而是绑定到 CompositeCollection。
此集合中的第一项是 ComboBoxItem 类型。
而且这种类型没有可以创建绑定的属性。
请注意绑定错误窗口中的“DataContext”列。
有一个 ComboBoxItem 类型,而不是 Category 类型。

要解决这个问题,您可以将具有必要值的新类别元素添加到 CompositeCollection 而不是 ComboBoxItem。
但是如果你创建一个静态的空实例会更方便。
然后,如果有必要,可以与它进行比较,以确定它虽然不为空,但它仍然是一个空实例。

    public class Category
    {
       // Some code

       public static Category Empty {get;} = new Category() {.....};
    }
<ComboBox x:Name="NewNewComboBox"
          SelectedValuePath="CompCategoryId"
          SelectedValue="{Binding CompCategoryId}"
          DisplayMemberPath="CategoryName"
          ItemsSource="{DynamicResource MyCollection}}">
    <ComboBox.Resources>
        <CompositeCollection x:Key="MyCollection">
            <x:Static Member="local:Category.Empty"/>
            <CollectionContainer Collection="{Binding Categories}"/>
        </CompositeCollection>
    </ComboBox.Resources>
</ComboBox>

P.S. 补充建议。 虽然使用 SelectedValue 和 SelectedValuePath 是可能的,但在 MVVM 概念中,当绑定到 ViewModel 属性时,我认为这是毫无意义的。
最好将 SelectedItem 绑定到 Category 类型的 ViewModel 属性。
根据我的个人经验,SelectedValue 和 SelectedValuePath 主要用于在 View “内部”实现解决方案时使用,而不使用 ViewModel 和 MVVM。

但我无法编辑它的 FontStyle...

要设置元素的样式,您必须将它们的数据上下文与空实例进行比较。
为此,您需要在某处创建它,然后才将其添加到集合中。
如果您只在 XAML 中执行此操作,则需要在资源中创建一个空实例。

<ComboBox x:Name="NewNewComboBox"
          SelectedValuePath="CompCategoryId"
          SelectedValue="{Binding CompCategoryId}"
          DisplayMemberPath="CategoryName"
          ItemsSource="{DynamicResource MyCollection}}"
          ItemContainerStyle="{DynamicResource itemStyle}">
    <ComboBox.Resources>
        <m:CompCategory x:Key="nullInstance"
                        CategoryName="(clear)"
                        CompCategoryId="0"/>
        <CompositeCollection x:Key="MyCollection">
            <StaticResource ResourceKey="nullInstance"/>
            <CollectionContainer Collection="{Binding Categories}"/>
        </CompositeCollection>
        <Style x:Key="itemStyle" TargetType="ComboBoxItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding}"
                             Value="{StaticResource nullInstance}">
                    <Setter Property="FontSize" Value="15"/>
                    <Setter Property="FontWeight" Value="Bold"/>
                    <Setter Property="FontFamily" Value="arial"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ComboBox.Resources>
</ComboBox>

我希望解决方案避免特定于 ComboBox 使用的类的代码,因为我想将此 ComboBox 作为 UserControl,以便它可以在不同的类上重用...

我认为这不是一个好主意。 UserControl 的主要目的是表示来自其 DataContext 属性的数据。 您希望 DataContext 收到什么? 如果你想要某种通用性,那么进入 DataContext 的所有类型都必须实现某种通用接口。 正是通过这个接口的实现,UserControl 将“理解”如何使用这些数据。 也许自定义控件会是您的任务更好的选择。

但要获得正确的建议,您需要更多关于您想要实施的细节。

【讨论】:

  • “附加推荐”是完全错误的。您当然可以通过视图模型中的“键”属性选择项目,因此 SelectedValue/SelectedValuePath 对 MVVM 非常有用。
  • 也许在一些非常罕见的任务中这是有道理的。但目前,我想不出一个这样的任务真正有意义的是使用 SelecteValue,而不是 SelectedItem。也许这是因为我的幻想太差了。
  • @EldHasp 可以添加一个样式触发器,以完成斜体字体样式、较小的字体大小和“(清除)”字符串作为空 catg 的内容。
  • @lidqy,你是对的。这是静态空实例的方便之处。通过将当前数据上下文的值与此空实例进行比较,您可以更改 ComboBox 元素的样式。我没有在示例中展示这个,因为在 TC 展示的代码中,所有元素的样式都是相同的。
  • @Clemens,当然,在附加推荐中,我会写下我的个人观点。这不是 WPF 文档。
【解决方案2】:

错误是由于您添加的“清除”项中缺少CompCategoryIdCategoryName。或者更确切地说,新添加的项目不是与集合的其余部分匹配的类型,并且没有与 DisplayMemberPath 和 SelectedValuePath 匹配的属性。

您可以创建一个表示Null Category 的对象。例如,

public class NullCategory:Category
{
  public NullCategory()
  {
    CompCategoryId = -1;
    CategoryName = "Clear";
  }
}

现在你可以像下面这样添加你的 Null 项目

 <CompositeCollection>
     <ViewModel:NullCategory />
     <CollectionContainer Collection="{Binding Source={StaticResource MyCollection}}"  />
</CompositeCollection>

【讨论】:

    猜你喜欢
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 2023-03-09
    • 2017-05-14
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    相关资源
    最近更新 更多