【问题标题】:How to bind a single property to the selection of two Controls in WPF?如何将单个属性绑定到 WPF 中两个控件的选择?
【发布时间】:2025-12-19 08:10:12
【问题描述】:

我有两个 DataGrid 填充了相同类型的不同对象集合。在我的 ViewModel 中,我有一个要绑定到当前选定对象的属性“CurrentObject”。

这意味着如果我在 DataGrid A 中选择一行,CurrentObject 将保存 DataGrid A 的选定项,如果我在 DataGrid B 中选择一行,CurrentObject 将保存 DataGrid B 的选定项。

在这两个 DataGrids 中,我已经完成了这样的绑定:

<DataGrid SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CurrentObject}">

只有当我在一个 DataGrid 中更改选择时,它才会按预期工作。如果我选择了一个已经选择的行,则 CurrentObject 属性不会更新,并且仍然引用来自其他 DataGrid 的对象。我猜这是因为当时没有触发 SelectionChanged 事件

【问题讨论】:

  • 你看过MultiBinding msdn.microsoft.com/en-us/library/…
  • MultiBinding 不是用于将多个属性绑定到单个控件。我需要它,反之亦然。如果我错了,请告诉我;-)
  • 你的意思是 CurrentObject 只有在 DataGridA 中的 selecteditem 更改为 DataGridB 时才改变?当您更改一个 DataGrid 中的选定项时它不会改变?
  • 您的用例很特殊 - 您希望 VM.CurrentObject 使用最近关注的网格的选定项进行更新。看起来您需要连接一些 Click 或 ItemSelected 代码隐藏类型处理程序。通常,如果值相同,您的 PropertyChange 处理程序将不会触发 - 例如您单击已选择的网格项目, SelectedItem 不会改变。因此没有更新。
  • 你是对的。这确实很奇怪,但就我而言,这是必要的。想象一下针对多个 DataGrid 中的对象的常见操作(例如编辑项目)。与其为每个 DataGrid 提供多个“编辑项”按钮的操作,我最好将焦点选择绑定到单个属性,并且只提供一个按钮。

标签: wpf wpfdatagrid


【解决方案1】:

清除 DataGrid 的 LostFocus 事件中的 SelectedItem:

示例:

 private void dg1_LostFocus(object sender, RoutedEventArgs e)
 {
        dg1.SelectedItem = null;
 }

 private void dg2_LostFocus(object sender, RoutedEventArgs e)
 {
        dg2.SelectedItem = null;
 }

因为如果 DataGrid 失去焦点时不清除 SelectedItem,DataGrid 仍然会记住 SelectedItem,如果再次选择该项目,SelectionChanged 事件将不会触发。

mvvm 示例:

 public void dg1_LostFocus(object sender, RoutedEventArgs e)
    {
        DataGrid dg = sender as DataGrid;
        if(dg != null)
        {
            dg.SelectedItem = null;
        }

    }

  <i:Interaction.Triggers>
            <i:EventTrigger EventName="LostFocus">
                <ei:CallMethodAction MethodName="dg1_LostFocus" TargetObject="{Binding}" />
            </i:EventTrigger>
  </i:Interaction.Triggers>

【讨论】:

  • 嗯,我试图严格避免 Code Behind,但你让我考虑处理焦点更改事件
  • 当然你可以避免使用代码隐藏,如果你使用 mvvm,请使用 i:Interaction ei:CallMethodAction 或其他人。
  • 看起来我们俩同时有相同的想法;-)
  • 我在这里看到的一个问题:当我想对所选项目调用操作时,我很可能会失去 DataGrids 焦点(例如单击按钮时),然后我的 SelectedItem 为空
  • @mamuesstack 是的,这是个问题
【解决方案2】:

我无法清楚地判断您使用的是事件还是绑定,但我假设您使用绑定方式。在这种情况下,请尝试将 IsSynchronizedWithCurrentItem 设置为 true。更多信息here

【讨论】:

  • 是的,我采用绑定方式。我已经使用同步,对我不起作用
  • 在这种情况下,您真的不需要任何触发器或其他任何东西。只需点击我的答案中的链接,您就会看到 WPF 自己管理双重选择...
  • 塞巴斯蒂安,我明白了。但是由于 ItemsSource 是两个独立的集合,因此无法进行同步,可以吗?
  • 绝对没问题;-)
【解决方案3】:

Rang 还提出了使用交互触发器来避免代码滞后的想法。看起来我们同时有同样的想法。他的方法是在额外的视图模型方法中处理 LostFocus 事件,我的方法是通过绑定处理 GotFocus。我觉得走哪条路是个人喜好。为了完整起见:

<iy:Interaction.Triggers>
    <iy:EventTrigger EventName="GotFocus">
        <is:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext}" 
                                 PropertyName="CurrentObject" 
                                 Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=SelectedValue}" />
    </iy:EventTrigger>
</iy:Interaction.Triggers>

由于仅在单个控件中更改选择时才更新绑定,因此当 DataGrid 获得焦点时,我还更改了属性

【讨论】:

  • 我收到了反对票。请告诉我我的回答有什么问题,因为我仍然最喜欢我的方法
最近更新 更多