2010-07-10 3 views
1

J'ai un DataGridCell qui contient un ComboBox. Je veux, que lorsque j'en déclenche l'événement 'SelectionChanged', une CollectionViewSource d'une colonne différente (éventuellement - à l'exécution, cellule) les Ressources de CellEditingTemplate doivent être remplies avec des données en fonction de la valeur sélectionnée pour cette ligne.Accéder aux enfants de DataGridCell à partir d'un autre DataGridCell?

Peut-être DataTrigger, ActionTrigger, EventTrigger, peut-être par code, XAML Je m'en fous, j'ai juste besoin d'une solution.

Merci beaucoup!

connexes: Accessing control between DataGridCells, dynamic cascading ComboBoxes

Répondre

4

Si je comprends bien votre question à droite, vous remplirez le contenu d'un combobox dans une cellule en fonction de la sélection d'un combobox dans une autre cellule qui se trouve dans la même ligne de le DataGrid. Si oui:

première solution (OMI le préférable)

Faire un ViewModel qui représente les données de lignes (une simple enveloppe autour de votre objet de données). Liez la propriété ItemsSource de la zone de liste déroulante de destination à un IEnumerable -property que vous fournissez à partir de votre viewmodel. Liez l'objet SelectedItem du composant ComboBox source à une autre propriété de votre ViewModel. Chaque fois que cette propriété-source change dans votre ViewModel, vous modifiez le contenu de la liste fournie par ViewModel.

Utilise pour la propriété de déstation (liste) a ObservableCollection<T>. La propriété source est à vous.

Voici un exemple approximatif. J'appelle la classe VM (pour ViewModel) mais cela ne change rien à votre solution actuelle. MVVM peut également être utilisé partiellement.

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); } 
    } 

} 

Ajouter un constructeur à cette classe qui prend votre objet de données et faire quelques propriétés wrapper pour le reste les propriétés que vous devez fournir dans le DataGrid. Si elles sont nombreuses, vous pouvez également créer une propriété qui fournit votre objet de données et la lie directement à celle-ci. Pas sympa, mais ça fera l'affaire. Vous pouvez également pré-initialiser la classe SelectedCategory avec les données de votre objet métier. Faites-le également dans le constructeur. En tant que ItemsSource pour le DataGrid, vous donnez un IEnumerable de la classe DataObjectVM qui enveloppe tous les éléments que vous souhaitez afficher.


Une manière alternative avec VisualTreeHelper

Si vous voulez le faire manuel, inscrivez-vous dans le code derrière un gestionnaire pour l'ComboBox.SelectionChangedEvent et puis changer le ItemsSource du manuel ComboBox de destination. L'objet métier que vous obtiendrez avec EventArgs. Le ComboBox de destination que vous devez rechercher dans l'arborescence visuelle (Utiliser le VisualTreeHelper). Les événements peuvent également être câblés si vous utilisez la classe DataGridTemplateColumn et ajoutez un DataTemplate avec les zones de liste déroulantes correspondantes.

Mais je pense que ce n'est vraiment pas très simple à faire et peut être sujet aux erreurs. La solution ci-dessus est beaucoup plus facile.

Voici le code que vous propably recherchez:

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); 
    } 
} 

Et c'est le balisage je:

<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> 

Accès au CollectionViewSource

Pour accéder au CollectionViewSource, mettez-le dans la section des ressources du DataTemplate correspondant, pas du panneau, alors vous aurez un ac direct cess à eux. IMO est de toute façon plus approprié que les ressources-conteneur de la grille.

Si vous voulez Dont't faire, vérifier l'état du poste suivant:

How to get logical tree of a DataTemplate

+0

Malheureusement, je ne pas utiliser MVVM dans ce projet, et je n'ai l'expérience avec MVVM encore. est-il possible de le faire avec WPF simple? puisque mes contraintes de temps ne me permettent pas de recréer tout le projet comme MVVM ou d'apprendre MVVM. Mais oui, vous avez bien compris, c'est mon désir. – Shimmy

+0

Ma question concerne la deuxième option. mon problème est juste la partie découverte, je ne sais pas comment trouver le cousin-combobox, je ne veux pas avoir une table d'adresse codée en dur, je veux toujours le garder dynamique en quelque sorte ... – Shimmy

+0

+1, Sons bon, on dirait que vous approchez de ce dont j'ai besoin, merci de mettre à jour votre réponse. Ce qui n'est pas encore résolu est que je veux avoir CollectionViewSource dans le (2ème) DataTemplate.Resources, pas un contrôle. va m'aider à chercher dans la ressource CollectionViewSource. – Shimmy

Questions connexes