2016-10-11 19 views
0

ComboBox 열이있는 DataGridView가 있습니다. 행에 따라 다른 옵션이 필요합니다. 값은 동일한 초기 목록을 기반으로해야하지만 이미 사용 된 값이 표시되지 않도록 필터링해야합니다.DataGridView ComboBox 열 동적 항목

예를 들어, 4 개의 드롭 다운 선택 : "A", "B", "C"및 "D"4 행. 처음에는 콤보 상자 열의 값으로 행을 설정하지 않습니다. 첫 번째 드롭 다운을 클릭하면 모든 선택 사항을 볼 수 있습니다. "A"를 선택한다고합시다. 이제 다른 행의 드롭 다운을 클릭하면 "A"가 이미 사용되었으므로 "B", "C"및 "D"만 볼 수 있습니다.

나는 항상 맨 위에 빈 옵션을 원합니다.

이렇게하면 DataRow 오류가 발생합니다. CellBox 및 CellBeginEdit을 사용하여 ComboBox를 동적으로 설정하려고했습니다. 두 경우 모두 나는 예기치 않은 행동을합니다. 이전에 설정된 값이 더 이상 선택 항목이 아니기 때문에 이미 선택한 값 행에 값이 변경되는 경우가 있습니다. 때로는 아무 일도 일어나지 않습니다.

필자는 Stack Exchange를 몇 시간 동안 모두 검색 했으므로 "솔루션"이 실제로 작동하지 않습니다.

편집 : 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