2016-10-11 126 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