【问题标题】:How to bind different properties to SelectedItem and SelectedIValue of ComboBox?如何将不同的属性绑定到 ComboBox 的 SelectedItem 和 SelectedIValue?
【发布时间】:2015-06-26 21:48:20
【问题描述】:

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

  • 为了能够在ComboBox中显示所选项目,当我进入编辑模式时,我将SelectedItem绑定到Mode
  • 为了能够将更改返回到 ViewModel,我将 SelectedValue 绑定到不同的属性。 (我需要绑定到不同的属性,因为“模式”每秒更新一次,并且会覆盖选定的值)。

问题在于,虽然SelectedItemMode=OneTime 绑定,但它仍然会触发SelectedValue 属性。我希望 SelectedValue 仅在用户选择一个值时触发。

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

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

【问题讨论】:

  • 至少对我来说还不清楚为什么StatusToSet 必须保持(空)直到实际用户选择?为什么不将选择推送到另一个属性SelectionChange 事件发生时?因为StatusToSet 有不需要的中间值?
  • @OmegaMan,应该是ModeToSet(我已经更新了)。当您在CellEditingTemplate 中执行SelectedItem="{Binding Mode}" 时,它会更新源。我不想在你刚进入编辑模式时更新它。

标签: c# wpf binding combobox


【解决方案1】:

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

为什么?

问题是尽管 SelectedItem 绑定了 Mode=OneTime 它 仍然触发 SelectedValue 属性。

应该如此。 OneTime 根据文档 (BindingMode Enumeration) 声明:

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

根据您的设计,数据上下文总是每秒更改一次。如果进一步阅读它的描述,它会声明

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

如果有人阅读 OneWay 绑定

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

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

我希望仅在用户选择一个值时触发 SelectedValue。

问题不是失控,而是正在发生的事情......

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

由于Mode 不断变化,它会将变化推入选择中,反之亦然。

修复建议

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


测试项目

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

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

<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";
}

【讨论】:

  • 我考虑了您的 cmets 并添加了附加属性 ModeToTest,它解决了问题。 &lt;ComboBox ItemsSource="{Binding Source={StaticResource Modes}}" SelectedItem="{Binding ModeToTest}" /&gt;
猜你喜欢
  • 1970-01-01
  • 2021-02-15
  • 1970-01-01
  • 2015-09-29
  • 2014-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
相关资源
最近更新 更多