6
votes

WPF - meilleure façon de supprimer un élément de l'itemSource

J'écris un itemsControl (un conteneur de document à onglets), dans lequel chaque élément (onglet) peut se retirer de l'interface utilisateur lorsque l'utilisateur la ferme. Cependant, je ne peux pas l'enlever directement à partir de la collection itemsControl.items , car les éléments peuvent être en tableau. Donc, je dois le supprimer du itemsSource , qui peut être n'importe quoi ( icollection , datatable , datasourceprovider .. .).

Dans le contexte de ma demande, je sais ce que le type réel du itemsSource sera, mais je veux que le contrôle soit plus générique afin que je puisse le réutiliser plus tard. < / p>

Je cherche donc un moyen de supprimer un élément d'une source de données, sans connaître son type. Je pourrais utiliser la réflexion, mais cela se sale ... Jusqu'à présent, la meilleure solution que j'ai proposée consiste à utiliser dynamique : xxx

mais je ' Je ne suis pas vraiment heureux avec ça, je suis sûr qu'il doit y avoir une meilleure façon. Toutes les suggestions seraient appréciées!


0 commentaires

4 Réponses :


-3
votes

La conception pratique dicte que vous devriez vraiment savoir ce que votre itemSource est et pouvoir le supprimer directement. La liaison met ensuite à jour automatiquement la vue du cours.

Toutefois, si vous êtes absolument intention d'une sorte de fonctionnalité générique pour le retrait, de jeter votre itemsSource à icollection ou icollection puis appelant supprimer sonne comme un moyen de parcourir mieux / plus fiable que d'utiliser les fonctionnalités dynamiques de .NET.


4 commentaires

En fait, une bonne conception garantirait que le itemsControl n'a aucune connaissance des types dans les éléments itemsSource du tout.


Je serais d'accord si j'avais le contrôle total sur cette propriété ArticleSource ... mais je ne le fais pas. Cela fait partie du WPF, est de type objet , et peut être tout ce qui supporte l'énumération. Et mon contrôle est conçu pour accepter quoi que ce soit, je ne veux pas me limiter à un type spécifique


@Thomas: Quel est le problème avec la solution de mon 2e paragraphe BTW?


Rien n'est faux, je ne suis pas celui qui vous a voté ... à propos de votre 2e paragraphe, malheureusement, je ne peux pas faire cela, car je ne connais pas le type d'élément réel et Icollection n'hérite pas de icollection



-1
votes

Comme vous l'avez trouvé, votre itemsControl n'a pas de connaissance intrinsèque des éléments liés - ces types sont fournis par les consommateurs de votre contrôle. Et vous ne pouvez pas modifier directement la collection car elle peut être liée aux données.

L'astuce consiste à assurer que chaque élément est enveloppé par une classe personnalisée (conteneur d'élément) de votre choix. Votre itemsControl Vous pouvez fournir ceci dans la méthode getcontainerforitemverride .

De là, vous pouvez définir des propriétés sur votre conteneur d'élément personnalisé que vous liez dans votre modèle par défaut. Par exemple, vous pouvez avoir une propriété appelée état qui change entre docked , flottant et fermé . Votre modèle utiliserait cette propriété pour déterminer comment - et si - pour montrer l'article.

Vous ne changerez pas du tout la source de données sous-jacente. Au lieu de cela, vous modifierez une couche spécifique au contrôle sur les éléments de données sous-jacents qui vous donnent les informations dont vous avez besoin pour implémenter votre contrôle.


3 commentaires

Kent, merci pour votre réponse. J'ai déjà créé un conteneur personnalisé et une nervure à la nervure GetContainerForItemoverride. Mais le fait est que je veux vraiment supprimer l'article de la collection sous-jacente, je ne veux pas simplement le cacher. Peut-être que je devrais simplement déléguer la mise en œuvre de «proches» à l'utilisateur, en manipulant un événement (code-derrière) ou à la liaison d'une commande (ViewModel)


@Thomas: pas de problème. Pouvez-vous expliquer pourquoi il est dont vous avez besoin de supprimer l'article? Peut-être qu'une vue de collection filtrée suffirait? Ou peut-être que votre article doit exécuter une commande lorsque l'utilisateur la ferme et que le retrait est à la hauteur du code consommateur. Il me semble que votre désir de créer un contrôle générique ne peut pas fonctionner si vous vous enlève.


Le contrôle affiche une liste de documents ouverts (feuilles de calcul SQL dans cette affaire). Il est lié à une liste de feuilles de calcul exposées par une vue de vue. Lorsque je clique sur le bouton Fermer sur un onglet (partie du modèle du TabdocumentContainerItem), le conteneur appelle le closab sur son parent (TabdocumentContainer), qui supprime le document de la collection de la feuille de calcul. En fait j'ai trouvé une solution, je vais le poster dans quelques minutes



12
votes

the itemCollection renvoyé par itemsControl.items ne vous permettra pas d'appeler supprimer directement, mais il implémente ieditablecollectionvoirview et vous permet d'appeler la méthode Supprimer dans cette interface.

Ceci ne fonctionnera que si la vue de la collection liée à itemSource implémente ieditablecollectionvoir lui-même. La vue de la collection par défaut sera pour la plupart des collections mutables, bien que non pour les objets qui implémentent ICollection mais pas ilist . xxx


2 commentaires

Réponse intéressante, je ne savais pas à propos de cette interface. Cependant, je pense que je vais coller à la solution que j'ai trouvée (voir ma réponse), car il est plus adéquat dans mon cas. De plus, si l'itemSource est un iéalable, CanRemove retournera FALSE, mais la viewModel pourrait avoir accès à la collection effective et être capable de supprimer l'article.


Solution géniale frère. Vous venez de résoudre un mauvais bogue pour moi: AvalONDock.CodePlex.com/workItem/13168



2
votes

OK, j'ai trouvé une solution ...

  • Si le itemsSource code> est la banquette, je soumettez un événement (à utiliser avec code-derrière) ou appelez une commande (à utiliser avec une vue de vue) pour supprimer l'élément de la itemSource code> collection. P> li>

  • Si ce n'est pas de la banquette, je soumette un événement pour inviter l'utilisateur à confirmer et je supprimai le conteneur directement à partir d'éléments code> p> p>

    public static readonly DependencyProperty CloseTabCommandProperty =
        DependencyProperty.Register(
            "CloseTabCommand",
            typeof(ICommand),
            typeof(TabDocumentContainer),
            new UIPropertyMetadata(null));
    
    public ICommand CloseTabCommand
    {
        get { return (ICommand)GetValue(CloseTabCommandProperty); }
        set { SetValue(CloseTabCommandProperty, value); }
    }
    
    public event EventHandler<RequestCloseTabEventArgs> RequestCloseTab;
    public event EventHandler<TabClosingEventArgs> TabClosing;
    
    internal void CloseTab(TabDocumentContainerItem tabDocumentContainerItem)
    {
        if (ItemsSource != null) // Databound
        {
            object item = ItemContainerGenerator.ItemFromContainer(tabDocumentContainerItem);
            if (item == null || item == DependencyProperty.UnsetValue)
            {
                return;
            }
            if (RequestCloseTab != null)
            {
                var args = new RequestCloseTabEventArgs(item);
                RequestCloseTab(this, args);
            }
            else if (CloseTabCommand != null)
            {
                if (CloseTabCommand.CanExecute(item))
                {
                    CloseTabCommand.Execute(item);
                }
            }
        }
        else // Not databound
        {
            if (TabClosing != null)
            {
                var args = new TabClosingEventArgs(tabDocumentContainerItem);
                TabClosing(this, args);
                if (args.Cancel)
                    return;
            }
            Items.Remove(tabDocumentContainerItem);
        }
    }
    


0 commentaires