如何给ComboBox的SelectedItem和SelectedIValue绑定不同的属性?

How to bind different properties to SelectedItem and SelectedIValue of ComboBox?

我有一个线程每秒更新当前 Mode 属性。我还想要一个能够在数据网格中的同一单元格内设置模式的选项。所以,在 not 编辑模式下,我只显示模式。在编辑模式下,我显示了一个已填充的 ComboBox。 现在,

问题是,尽管 SelectedItemMode=OneTime 绑定,但它仍然会触发 SelectedValue 属性。我希望 SelectedValue 仅在用户 select 一个值时被触发。

我希望我想做的很清楚。那么,我该如何实现呢?欢迎使用其他方法(即使我需要使用不同的控件)。

<DataGridTemplateColumn Header="Mode">
  <DataGridTemplateColumn.CellTemplate>
      <DataTemplate>
          <TextBlock Text="{Binding Mode}"/>
      </DataTemplate>
  </DataGridTemplateColumn.CellTemplate>
  <DataGridTemplateColumn.CellEditingTemplate>
     <DataTemplate>
        <ComboBox ItemsSource="{Binding Source={StaticResource Modes}}"
                  SelectedItem="{Binding Mode, Mode=OneTime}"
                  SelectedValue="{Binding ModeToSet, Mode=OneWayToSource}" 
         />
     </DataTemplate>
  </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

由于组合框的工作方式以及 Mode 在后台不断变化的方式,无法实现需要完成的前提。

为什么?

The problem is that though SelectedItem is bound with Mode=OneTime it still triggers SelectedValue property.

这是应该的。 OneTime 根据文档 (BindingMode Enumeration) 指出:

"在应用程序启动或数据上下文更改时更新绑定目标。"

根据您的设计,数据上下文总是每秒变化一次。如果进一步阅读说明

"如果您使用的数据适合使用当前状态的快照或数据是真正静态的,那么这种类型的绑定是合适的。...这本质上是一种更简单的形式单向绑定..."

如果有人阅读 OneWay 绑定

"当绑定源 (source) 更改时更新绑定目标 (target) 属性。如果被绑定的控件是隐式只读的,则此类型的绑定是合适的。"

组合框的最终设计目的是同时更改 SelectedItem 并将 SelectedItem 的值变为 SelectedValue

I want the SelectedValue to be triggered only when user select a value.

问题不是失控,而是进来的东西....

创建一个测试项目,组合框按照您指定的方式运行,选定的值仅在用户选择一个值时触发。组合框仅在做出选择 或外部值更改一个 时设置 SelectedX 属性,因此它会更改另一个。

由于 Mode 不断变化,它会将变化推送到选择中,而不是相反。

修复建议

我建议您拍摄模式快照并将其放入 ModeOnEdit 变量并绑定它。当用户做出选择时,捕获事件并更改实际的 Mode.


测试项目

绑定到您自己的数据源,我的是 Ships。 Ships 是一个列表,其中 Name 作为该对象上的 属性。 ToString 在船对象上 returns Name.

这是结果,有两个文本框显示所选 item/value 的状态。用于设置所选值和组合框本身的按钮。

<Label Grid.Row="1" Grid.Column="1">SelectedItem</Label>
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding SelectedItem, ElementName=cbMain}"/>
<Label Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2">SelectedValue</Label>
<TextBlock Grid.Row="3" Grid.Column="2" Text="{Binding SelectedValue, ElementName=cbMain}"/>
<Button Grid.Row="5" Grid.Column="1" Click="ChangeSelectedValue">Set Selected Value</Button>
<ComboBox Name="cbMain"
            Grid.Row="5"
            Grid.Column="2"
            ItemsSource="{Binding Ships}"
            SelectedValuePath="Name"/>

-- 代码隐藏

private void ChangeSelectedValue(object sender, RoutedEventArgs e)
{
    cbMain.SelectedValue = "Pacific Silver";
}