2010-07-10 3 views
1

У меня есть DataGridCell, который содержит ComboBox.Доступ к данным DataGridCell из другого DataGridCell?

Я хочу, чтобы при запуске события «SelectionChanged» CollectionViewSource другого столбца (в конечном итоге - во время выполнения, ячейка) ресурсы CellEditingTemplate должны заполняться данными в соответствии с выбранным значением для этой строки.

Возможно, DataTrigger, ActionTrigger, EventTrigger, может быть, кодом, XAML Мне все равно, мне просто нужно решение.

Большое спасибо!

Похожие: Accessing control between DataGridCells, dynamic cascading ComboBoxes

ответ

4

Если я правильно понял ваш вопрос правильно, вы будете заполнить содержимое выпадающего списка в ячейке на основе выбора выпадающего списка в другой ячейке, которая находится в той же строке DataGrid. Если да:

Первого решение (ИМО предпочтительное)

Сделать ViewModel, который представляет данные строки (простую обертку вокруг вашего объекта данных). Привяжите свойство ItemsSource целевого ComboBox к IEnumerable-свойствам, которые вы предоставляете из своей модели просмотра. Привяжите SelectedItem из source-ComboBox к другому свойству ViewModel. Каждый раз, когда это свойство-свойство изменяется в вашей ViewModel, вы изменяете содержимое списка, предоставленного ViewModel.

Использовать для уничтожения (списка) объекта a ObservableCollection<T>. Свойство источника зависит от вас.

Вот пример. Я вызываю класс VM (для ViewModel), но это ничего не меняет в вашем текущем решении. MVVM также может использоваться частично.

public class DataObjectVM : DependencyObject { 

    public static readonly DependencyProperty SelectedCategoryProperty = 
     DependencyProperty.Register("SelectedCategory", typeof(CategoryClass), typeof(DataObjectVM), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,delegate (DependencyObject d,DependencyPropertyChangedEventArgs e){ 
      ((DataObjectVM)d).SelectedCategoryChanged(e); 
     })); 

    ObservableCollection<ItemClass> _items=new ObservableCollection<ItemClass>(); 


    void SelectedCategoryChanged(DependencyPropertyChangedEventArgs e) { 

     // Change here the contents of the _items collection. 
     // The destination ComboBox will update as you desire 
     // Do not change the _items reference. Only clear, add, remove or 
     // rearange the collection-items 

    } 

    // Bind the destination ComboxBox.ItemsSource to this property 
    public IEnumerable<ItemClass> DestinationItems { 
     get { 
      return _items; 
     } 
    } 
    // Bind to this property with the source ComboBox.SelectedItem 
    public CategoryClass SelectedCategory { 
     get { return (CategoryClass)GetValue(SelectedCategoryProperty); } 
     set { SetValue(SelectedCategoryProperty, value); } 
    } 

} 

Добавьте конструктор этого класса, который принимает ваш объект данных и сделать некоторые свойства оболочки для остальных свойств, нужно предоставить в DataGrid. Если они много, вы также можете создать одно свойство, которое предоставляет объект данных и привязку к нему напрямую. Нехорошо, но это сработает. Вы также можете (необходимо) предварительно инициализировать выбранную категорию данными из вашего бизнес-объекта. Сделайте это также и в конструкторе. В качестве источника Items для DataGrid вы предоставляете IEnumerable класса DataObjectVM, который обертывает все элементы, которые вы хотите показать.


Альтернативный способ с VisualTreeHelper

Если вы хотите сделать это руководство, прописать в коде позади обработчика для ComboBox.SelectionChangedEvent и изменения затем ItemsSource в руководстве назначения ComboBox. Бизнес-объект, который вы получите с EventArgs. Конечный ComboBox, который вы должны искать в визуальном дереве (используйте VisualTreeHelper). События могут быть подключены также, если вы используете класс DataGridTemplateColumn и добавьте DataTemplate с соответствующими ComboBoxes.

Но я думаю, что это действительно не очень просто сделать и может быть подвержено ошибкам. Вышеупомянутое решение намного проще.

Вот код, который вы Propably ищете:

private void CboSource_SelectionChanged(object sender, SelectionChangedEventArgs e) { 
    ComboBox cbo = (ComboBox)sender; 
    FrameworkElement currentFe = VisualTreeHelper.GetParent(cbo) as FrameworkElement; 
    while (null != currentFe && !(currentFe is DataGridRow)) { 
     currentFe = VisualTreeHelper.GetParent(currentFe) as FrameworkElement; 
    } 
    if (null != currentFe) { 
     List<ComboBox> list = new List<ComboBox>(); 
     FindChildFrameworkElementsOfType<ComboBox>(currentFe,list); 
     // Requirement 1: Find ComboBox 
     foreach (ComboBox cboFound in list) { 
      if (cboFound.Name == "PART_CboDestination") { 
       // This is the desired ComboBox 
       // Your BO is available through cbo.Found.DataContext property 
       // If don't like to check the name, you can also depend on the 
       // sequence of the cbo's because I search them in a deep search 
       // operation. The sequence will be fix. 
      } 
     } 

     List<DataGridCell> cells = new List<DataGridCell>(); 
     FindChildFrameworkElementsOfType<DataGridCell>(currentFe,cells); 
     // Requirement 2: Find Sibling Cell 
     foreach (DataGridCell cell in cells) { 
      // Here you have the desired cell of the other post 
      // Take the sibling you are interested in 
      // The sequence is as you expect it 

      DataGridTemplateColumn col=cell.Column as DataGridTemplateColumn; 
      DataTemplate template = col.CellTemplate; 

      // Through template.Resources you can access the CollectionViewSources 
      // if they are placed in the CellTemplate. 
      // Change this code if you will have an edit cell template or another 
      // another construction 

     } 
    }    
} 

void FindChildFrameworkElementsOfType<T>(DependencyObject parent,IList<T> list) where T: FrameworkElement{    
    DependencyObject child; 
    for(int i=0;i< VisualTreeHelper.GetChildrenCount(parent);i++){    
     child = VisualTreeHelper.GetChild(parent, i); 
     if (child is T) { 
      list.Add((T)child); 
     } 
     FindChildFrameworkElementsOfType<T>(child,list); 
    } 
} 

И это разметка я использовал:

<DataGrid.Columns>       
    <DataGridTemplateColumn Header="Source" > 
     <DataGridTemplateColumn.CellTemplate> 
      <DataTemplate> 
       <ComboBox Name="PART_CboSource" SelectionChanged="CboSource_SelectionChanged" ItemsSource="!!YOUR ITEMS SOURCE!!" SelectedItem="{Binding Category}">        
       </ComboBox> 
      </DataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 
    <DataGridTemplateColumn Header="Destination"> 
     <DataGridTemplateColumn.CellTemplate> 
      <DataTemplate> 
       <ComboBox Name="PART_CboDestination"/> 
      </DataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 
</DataGrid.Columns> 

Доступ к CollectionViewSource

Чтобы получить доступ к CollectionViewSource, поместите его в раздел ресурсов соответствующего DataTemplate, а не панели, тогда у вас будет прямой ac к ним. ИМО - это местоположение в любом случае более подходящее, чем контейнер ресурсов сетки.

Если вы dont't хотят сделать это, проверьте состояние следующего поста:

How to get logical tree of a DataTemplate

+0

К сожалению, я не использую MVVM в этом проекте, и у меня есть опыт работы с MVVM еще. возможно ли это сделать с помощью простого WPF? поскольку мои временные ограничения не позволяют мне воссоздать весь проект как MVVM или узнать MVVM. Но да, вы хорошо поняли, это мое желание. – Shimmy

+0

Мой вопрос касается второго варианта. моя проблема - это только часть поиска, я не знаю, как найти кузена-combobox, я не хочу иметь жестко закодированную адресную таблицу, я все равно хочу, чтобы она была динамичной ... – Shimmy

+0

+1, Звуки хорошо, похоже, что вы приближаетесь к тому, что мне нужно, спасибо за обновление вашего ответа. Что еще не решено, так это то, что я хочу иметь CollectionViewSource в (2) DataTemplate.Resources, а не в Control. поможет мне найти ресурс CollectionViewSource. – Shimmy