DataGridView ComboBox 列动态项

Posted

技术标签:

【中文标题】DataGridView ComboBox 列动态项【英文标题】:DataGridView ComboBox column dynamic items 【发布时间】:2016-10-11 00:37:26 【问题描述】:

我有一个带有 ComboBox 列的 DataGridView。我需要它根据行有不同的选项。这些值需要基于相同的初始列表,但经过过滤以不显示任何已使用的值。

例如,我有 4 个下拉选项:“A”、“B”、“C”和“D”,共 4 行。最初,没有为组合框列设置任何行值。我单击的第一个下拉菜单应该会看到所有选项。假设我选择“A”。现在,如果我点击另一行的下拉菜单,我现在应该只会看到“B”、“C”和“D”,因为“A”已经被使用了。

我也想一直在顶部有一个空选项。

当我尝试这样做时,我得到一个 DataRow 错误。我尝试使用 CellClick 和 CellBeginEdit 动态设置 ComboBox。在这两种情况下,我都会遇到意外行为。有时已经选择的值行的值会发生变化,因为先前设置的值不再在选择中。有时什么都不会发生。

请注意,我已经准备好几个小时搜索 Stack Exchange,但没有一个“解决方案”真正起作用。

编辑:似乎通过使用 CellBeginEdit 设置 ComboBox 项,基础数据很好。问题只是组合框中显示的选定值。如果我只选择单元格而不下拉组合框,则值会刷新到应有的值。

【问题讨论】:

【参考方案1】:

是的,因为 DataGridView 试图在每个 DataTemplate 实例化中缓存和重用 ComboBox,所以要正确处理是很棘手的。我有一个类似的情况,我想要一个“过滤”组合框,它根据用户迄今为止在单元格中键入的内容过滤可用选项列表,这是您尝试做的极端版本​​,所以同样的技巧应该管用。新的 FilterChanged 事件可用于绑定可根据需要更新组合框列表项的代码。在您的事业中,您还可以在 FilteringComboBox 上收听 DataContextChanged 事件。

<DataTemplate x:Key="myTemplateSplitPayeeEdit">
    <local:FilteringComboBox Style="StaticResource GridComboStyle"
              SelectedItem="Binding PayeeOrTransferCaption, Mode=TwoWay"
              ItemsSource="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type views:TransactionsView, Path=PayeesAndTransferNames" 
              PreviewLostKeyboardFocus="ComboBoxForPayee_PreviewLostKeyboardFocus"  
              FilterChanged="ComboBoxForPayee_FilterChanged"
             >
        <ComboBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </ComboBox.ItemsPanel>
    </local:FilteringComboBox>
</DataTemplate>


    private void ComboBoxForPayee_FilterChanged(object sender, RoutedEventArgs e)
    
        FilteringComboBox combo = sender as FilteringComboBox;
        combo.FilterPredicate = new Predicate<object>((o) =>  return o.ToString().IndexOf(combo.Filter, StringComparison.OrdinalIgnoreCase) >= 0; );
    


public class FilteringComboBox : ComboBox

    public static RoutedEvent FilterChangedEvent = EventManager.RegisterRoutedEvent("FilterChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FilteringComboBox));

    public event RoutedEventHandler FilterChanged;

    ListCollectionView view;

    protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
    
        Filter = null;
        Items.Filter = null;
        this.view = newValue as ListCollectionView;
        base.OnItemsSourceChanged(oldValue, newValue);
    

    public Predicate<object> FilterPredicate
    
        get  return view.Filter; 
        set  view.Filter = value; 
    

    public override void OnApplyTemplate()
                
        base.OnApplyTemplate();
        TextBox edit = this.Template.FindName("PART_EditableTextBox", this) as TextBox;
        if (edit != null)
        
            edit.KeyUp += new System.Windows.Input.KeyEventHandler(OnEditKeyUp);
        
    

    void OnEditKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    
        TextBox box = (TextBox)sender;
        string filter = box.Text;
        if (string.IsNullOrEmpty(filter))
        
            Items.Filter = null;
        
        else if (box.SelectionLength < filter.Length)
        
            if (box.SelectionStart >= 0)
            
                filter = filter.Substring(0, box.SelectionStart);
            
            SetFilter(filter);
        
    

    public string Filter  
        get; set; 
    

    void SetFilter(string text)
    
        Filter = text;
        var e = new RoutedEventArgs(FilterChangedEvent);
        if (FilterChanged != null)
        
            FilterChanged(this, e);
        
        RaiseEvent(e);
    

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    
        base.OnSelectionChanged(e);
    


【讨论】:

看来您正在使用 WPF。 WinForms 有什么解决方案吗?

以上是关于DataGridView ComboBox 列动态项的主要内容,如果未能解决你的问题,请参考以下文章

C# datagridview中添加了一列ComboBox列,这个ComboBox列下拉怎么获取到txt文档里面的数据?

DataGridView 设置列单元格 Combobox

winform datagridview中combobox列改变选项时触发其他列变化

单击组合框值时 DataGridView 列标题更改

2021-11-22 WinFrom面试题 DataGridView中添加了一个ComboBox列,如何使用?

C# winform 把datagridview一列分别显示在combobox里