2016-10-11 44 views
0

私は、ComboBox列を持つDataGridViewを持っています。私はそれが行に応じて異なるオプションを持つ必要があります。値は、同じ初期リストに基づいている必要がありますが、すでに使用されている値は表示されないようにフィルタリングされています。DataGridView ComboBox列の動的項目

たとえば、4つの行で「A」、「B」、「C」および「D」の4つのドロップダウン選択肢があります。最初は、コンボボックスの列の値には何も設定されていません。最初のドロップダウンをクリックすると、すべての選択肢が表示されます。 「A」を選択したとしましょう。今度は、別の行のドロップダウンをクリックすると、 "A"がすでに使用されているため、 "B"、 "C"、 "D"のみ表示されます。

また、常に空のオプションがトップに表示されます。

これを実行しようとすると、DataRowエラーが発生します。私は、CellBoxとCellBeginEditを使ってComboBoxを動的に設定しようとしました。どちらの場合も、予期しない動作が発生します。以前に設定された値がもはや選択肢に含まれていないため、すでに選択されている値の行には値が変更されることがあります。場合によっては何も起こらないことがあります。

ちょうどメモとして、私はStack Exchangeを数時間探していました。すべての準備ができていて、 "解決策"のどれも実際には動作しません。

EDIT:CellBeginEditを使用してComboBoxアイテムを設定すると、基になるデータは正常です。コンボボックスに表示されている選択された値だけです。コンボボックスをドロップダウンせずにセルを選択するだけで、値が更新されます。

答えて

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

関連する問題