2016-10-11 125 views
0

我有一个DataGridView ComboBox列。我需要它根据行有不同的选项。这些值需要基于相同的初始列表,但过滤后不显示任何已使用的值。例如,我有4个下拉选项:“A”,“B”,“C”和“D”,4行。最初没有行设置为组合框列的任何值。首先点击下拉我应该看到所有的选择。假设我选择“A”。现在,如果我点击另一行的下拉菜单,现在只应看到“B”,“C”和“D”,因为已经使用了“A”。DataGridView ComboBox列动态项目

我还想在顶部一直有空的选项。

当我尝试这样做时,我得到一个DataRow错误。我曾尝试使用CellClick和CellBeginEdit动态设置ComboBox。在这两种情况下,我都会出现意外的行为有时候,已选定的值行将会改变值,因为之前设置的值不再在选项中。有时什么都没有发生。

就像一个笔记,我已经搜索了堆栈交换几个小时都准备好了,没有任何“解决方案”实际工作。

编辑:它似乎通过使用CellBeginEdit来设置组合框项目的底层数据是好的。只是在组合框中显示的选定值是问题。如果我只是选择单元格而不放下组合框,则值会刷新到应该显示的位置。

回答

0

对,因为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); 
    } 

} 
+0

看来您正在使用WPF。任何解决方案的WinForms? – James