【问题标题】:Binding the same Collection to ComboBox and Datagrid将同一个集合绑定到 ComboBox 和 Datagrid
【发布时间】:2017-07-14 12:16:39
【问题描述】:

GitHub 链接:https://github.com/babakin34/wpf_test/tree/master/WpfApp1

我有以下课程:

视图模型


public class PersonVM : BindableBase
{
  public int ID { get; set; }

  private string _lastName;
  public string LastName
  {
      get { return _lastName; }
      set { SetProperty(ref _lastName, value); }
  }
}

public class MainVM : BindableBase
{
  public ObservableCollection<PersonVM> People { get; set; }

  private PersonVM _selectedPerson;
  public PersonVM SelectedPerson
  {
      get { return _selectedPerson; }
      set { SetProperty(ref _selectedPerson, value); }
  }

  public MainVM()
  {
      People = new ObservableCollection<PersonVM>()
      {
          new PersonVM()
          {
              ID = 1,
              LastName = "AA"
          },
          new PersonVM()
          {
              ID = 2,
              LastName = "BB"
          },
      };

      SelectedPerson = People.First();
  }
}

查看


<Grid>
    <StackPanel>
        <ComboBox ItemsSource="{Binding People}" 
                  SelectedItem="{Binding SelectedPerson}"
                  DisplayMemberPath="LastName" 
                  Margin="0,5,0,25"/>

        <DataGrid ItemsSource="{Binding People}"/>
    </StackPanel>
</Grid>


如何实现当用户选择空元素时通知 ComboBox 中的“MainVM.SelectedPerson”,这是由 Datagrid 的默认最后一个条目引起的?

PS:我正在使用 Prism,但问题与 Prism 无关。您可以将 BindableBase 替换为 INotifyPropertyChanged。

【问题讨论】:

  • 您也应该将SelectedItem="{Binding SelectedPerson}" 添加到DataGrid
  • 您可以将 DataGrid 的 CanUserAddRows 属性设置为 false 以摆脱最后一个空行。这不是可以在 ComboBox 中选择的实际 PersonVM,而是用于向 DataGrid 添加新项目的占位符...
  • @mm8:我需要 DataGrid 的最后一行,以便用户可以添加新条目。
  • So what do you expect to show in the ComboBox when this row is selected?
  • @Panagiotis Kanavos:它对 ComboBox 没有影响。

标签: c# .net wpf xaml prism


【解决方案1】:

编辑: 这里的真正问题与我起初想的有点不同。选择插入行时,您会在输出窗口中看到 WPF 无法将“NamedObject”转换为“PersonVM”。 Datagrid 为要使用的插入行创建了一个 NamedObject,但绑定根本不起作用,因为它的类型错误。 干净简单的解决方案是创建一个转换器来检查对象是否为 PersonVM 类型,否则返回 null(而不是 NamedObject 实例)。

public class MyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is PersonVM)
            return value;
        return null;
    }
}

在 xaml 中

<DataGrid x:Name="DataGrid"
                  ItemsSource="{Binding People}"
                  SelectedCellsChanged="DataGrid_OnSelectedCellsChanged"
                  SelectedItem="{Binding SelectedPerson,
                                         Converter={StaticResource myConverter}}"


又旧又脏

不是最好的方法,但如果您不介意在代码隐藏中使用视图模型(或通过接口抽象它),您可以使用“SelectionChanged”事件将 ViewModel 中的 SelectedPerson 设置为 null(如果有)所选项目不是您需要的类型。

private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        bool invalidStuffSelected = false;
        //throw new System.NotImplementedException();
        foreach (var obj in DataGrid.SelectedItems)
        {
            if (!(obj is PersonVM))
                invalidStuffSelected = true;
        }
        MainVM vm = (MainVM) this.DataContext;
        if (invalidStuffSelected)
            vm.SelectedPerson = null;
    }

在您的示例中,选择模式“single”会更有意义,因为组合框只能显示一个选定值。

【讨论】:

  • 我已经用类似的方法解决了。我只想知道是否可以不使用代码背后的代码或任何肮脏的黑客攻击。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 2014-09-04
  • 1970-01-01
  • 2010-09-23
相关资源
最近更新 更多