2016-10-11 1 views
0

Ich habe ein DataGridView mit einer ComboBox-Spalte. Ich brauche es verschiedene Optionen je nach Zeile. Die Werte müssen auf derselben Ausgangsliste basieren, aber gefiltert sein, um keine bereits verwendeten Werte anzuzeigen.Dynamische Elemente der DataGridView ComboBox-Spalte

Zum Beispiel habe ich 4 Dropdown-Optionen: "A", "B", "C" und "D" mit 4 Zeilen. Anfangs werden keine Zeilen auf einen Wert für die Kombinationsfeldspalte gesetzt. Das erste Drop-Down-Fenster, auf das ich klicke, sollte alle Optionen anzeigen. Sagen wir, ich wähle "A". Wenn ich jetzt auf die Drop-Down-Taste in einer anderen Zeile klicke, sollte ich nur noch "B", "C" und "D" sehen, weil "A" bereits benutzt wird.

Ich möchte auch eine leere Option an der Spitze die ganze Zeit.

Wenn ich dies versuche, bekomme ich einen DataRow-Fehler. Ich habe versucht, die ComboBox dynamisch mit CellClick und CellBeginEdit zu setzen. In beiden Fällen bekomme ich unerwartetes Verhalten. Bei einigen Zeilen mit bereits ausgewählten Werten wird der Wert nur geändert, weil der zuvor festgelegte Wert nicht mehr in den Auswahlmöglichkeiten enthalten ist. Manchmal passiert überhaupt nichts.

Nur als eine Anmerkung, ich habe Stack Exchange für ein paar Stunden alle bereit und keine der "Lösungen" tatsächlich funktioniert.

EDIT: Es scheint, dass durch die Verwendung von CellBeginEdit, um die ComboBox-Elemente die zugrunde liegenden Daten in Ordnung ist. Es ist nur der ausgewählte Wert, der im Kombinationsfeld angezeigt wird. Wenn ich nur die Zelle auswähle, ohne das Kombinationsfeld zu verlassen, wird der Wert aktualisiert, so wie er sein sollte.

Antwort

0

Ja, es ist schwierig, richtig zu machen, weil DataGridView versucht, die ComboBox in jeder DataTemplate-Instanziierung zwischenzuspeichern und wiederzuverwenden. Ich habe einen ähnlichen Fall, wo ich eine "Filter" Combobox, die die Liste der verfügbaren Auswahlmöglichkeiten basierend auf was der Benutzer hat so weit in die Zelle, die eine extreme Version von dem, was Sie versuchen, ist zu tun, so der gleiche Trick gefiltert sollte arbeiten. Das neue FilterChanged-Ereignis kann zum Binden an Code verwendet werden, der die Combobox-Listenelemente nach Bedarf aktualisieren kann. In Ihrer Ursache könnten Sie auch das DataContextChanged-Ereignis auf der FilteringComboBox abhören.

<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

Es scheint, dass Sie WPF verwenden. Irgendwelche Lösungen für WinForms? – James

Verwandte Themen