如何在WPF DataGrid中实现可编辑的DataGridComboBoxColumn

Ale*_*aum 18 wpf binding datagrid datagridcomboboxcolumn

我想让用户能够编辑WPF DataGrid中的一些数据(来自.net Framework 4.0)."仪器"列应允许用户从静态列表中选择可用的仪器或写入自由文本.我的DataGrid使用MVVM绑定到数据.我尝试了很多我在互联网上找到的解决方案,但没有一个能正常工作.这是我的代码:

<DataGrid Margin="0,6" ItemsSource="{Binding Path=Orders}" AutoGenerateColumns="False"  CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="True">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Instrument" MinWidth="140"                                      
 ItemsSource="{x:Static ViewModel.Instruments}" SelectedItemBinding="{Binding Path=SelectedInstrument}">
 <DataGridComboBoxColumn.EditingElementStyle>
   <Style TargetType="ComboBox">
     <Setter Property="IsEditable" Value="True"/>
   </Style>                  
 </DataGridComboBoxColumn.EditingElementStyle>                
</DataGridComboBoxColumn>   
</DataGrid.Columns>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)

下拉列表正确显示.可以使用任何文本编辑该字段,但在为自由文本关闭下拉列表后,它会为SelectedInstrument设置null.它仅适用于所选项目.我试图更改为SelectedValueBinding,但它没有帮助.

如何正确实施这一要求?有人可以在这里发布工作样本吗?

附加:订单是ObservableCollection Order具有类似字符串Title,DateTime Ordered,string SelectedInstrument,Instruments是一个字符串[]的属性

解决方案:以下建议作为bathineni工作的解决方法:

<DataGrid Margin="0,6" ItemsSource="{Binding Path=Orders}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="True">
 <DataGrid.Columns>
  <DataGridTemplateColumn Header="Instrument" MinWidth="140">
   <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
     <TextBlock Text="{Binding Path=SelectedInstrument, Mode=OneWay}"/>
    </DataTemplate>
   </DataGridTemplateColumn.CellTemplate>
   <DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
     <ComboBox IsEditable="True" Text="{Binding Path=SelectedInstrument}" 
      ItemsSource="{x:Static ViewModel.Instruments}"/>                   
    </DataTemplate>
   </DataGridTemplateColumn.CellEditingTemplate>
  </DataGridTemplateColumn>   
 </DataGrid.Columns>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)

Bat*_*eni 16

发生这种情况是因为输入的自由文本是字符串类型和所选项目你绑定到comboBox的是一些复杂的类型....

而不是使用DataGridComboBoxColumnuse DataGridTemplateColumn,你可以将TextcomboBox的属性绑定到某个属性,该属性将在关闭下拉列表后保存自由文本值.

通过查看以下示例,您可以获得更好的主意.

<DataGrid>
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox IsEditable="True" 
                              Text="{Binding NewItem}" 
                              ItemsSource="{Binding Sourcelist.Files}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)

  • 这是一个糟糕的用户体验.您必须在此列中选择一次,然后第二次将选项卡标记到组合框中.数据网格中的所有其他列只需要1个选项卡,此选项需要按两次选项卡. (5认同)

WPF*_*-it 5

尝试仅使用SelectedValue,但同时使用DisplayMemberPath和TextSearch.TextPath.

   <ComboBox IsEditable="True" DisplayMemberPath="MyDisplayProperty" SelectedValuePath="MyValueProperty" SelectedValue="{Binding MyViewModelValueProperty}" TextSearch.TextPath="MyDisplayProperty" />
Run Code Online (Sandbox Code Playgroud)

对于可编辑的组合框,我们必须同步组合选择的值,项显示的值以及我们必须根据用户输入搜索的值.

但如果您使用字符串集合来绑定您的组合框,那么您可以尝试以下...

  1. 在ViewModel中添加一个名为InstrumentsView的新属性.这将返回一个新的ListCollectionView.

    public static string ListCollectionView InstrumentsView
    {
            get
            {
                    return new ListCollectionView(Instruments);
            }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将DataGridComboBoxColumn XAML更改为如下...

    <DataGridComboBoxColumn Header="Instrument" MinWidth="140"
                            ItemsSource="{x:Static ViewModel.InstrumentsView}">
            <DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="ComboBox">
                            <Setter Property="IsEditable" Value="True"/>
                            <Setter Property="IsSynchronizedWithCurrentItem" Value=True" />
                            <Setter Property="SelectedItem" Value="{Binding SelectedInstrument, Mode=OneWayToSource}" /> <!-- Assuming that SelectedInstrument is string  -->
                    </Style>
            </DataGridComboBoxColumn.EditingElementStyle>
    </DataGridComboBoxColumn>
    
    Run Code Online (Sandbox Code Playgroud)

告诉我这是否有效......


vvn*_*rmi 5

您可以通过子类化来创建自己的 ComboBox 列类型DataGridBoundColumn。与 Bathineni 的子类化解决方案相比,DataGridTemplateColumn以下解决方案具有更好的用户体验(无双选项卡),并且您有更多选项可以根据您的特定需求调整列。

public class DataGridComboBoxColumn : DataGridBoundColumn {
    public Binding ItemsSourceBinding { get; set; }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) {
        var textBox = new TextBlock();
        BindingOperations.SetBinding(textBox, TextBlock.TextProperty, Binding);
        return textBox;
    }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) {
        var comboBox = new ComboBox { IsEditable = true };
        BindingOperations.SetBinding(comboBox, ComboBox.TextProperty, Binding);
        BindingOperations.SetBinding(comboBox, ComboBox.ItemsSourceProperty, ItemsSourceBinding);
        return comboBox;
    }

    protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs) {
        var comboBox = editingElement as ComboBox;
        if (comboBox == null) return null;

        comboBox.Focus(); // This solves the double-tabbing problem that Nick mentioned.
        return comboBox.Text;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以像这样使用该组件。

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding MyItems}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
        <local:DataGridComboBoxColumn Header="Thingy" Binding="{Binding Thingy}"
            ItemsSourceBinding="{Binding
                RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}},
                Path=Thingies}"/>
    </DataGrid.Columns>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)

我通过对类似问题的回答得到了这个解决方案。