2010-03-25 9 views
14

Ainsi, l'appel de méthode InitializeComponent dans le constructeur de Windows s'exécute via le XML et ajoute les contrôles et les branche dans leurs événements. Par conséquent, lorsqu'une propriété de l'un des contrôles change, elle appelle la méthode qui s'abonne à l'événement. La méthode fait référence à un contrôle qui n'a pas encore été construit. Pourquoi cela se passe-t-il dans cet ordre ici? Cela a fonctionné dans WinForms parce que les événements n'étaient pas tirés plus tard, après que tous les contrôles aient été créés. Y a-t-il un moyen de forcer cela dans WPF?WPF Obtention d'une référence null de commande pendant InitializeComponent

Les autres solutions que je vois sont

  • Je dois souscrire aux événements après l'initialisation.

  • Je dois vérifier null quand je fais affaire avec un contrôle.

+0

Il serait utile de savoir spécifiquement quels événements sont à l'origine du problème - pouvez-vous ajouter un peu plus de détails? Cependant, je soupçonne que la réponse pourrait être votre premier point ... –

+0

Pouvez-vous expliquer plus de l'architecture? Je suis curieux de savoir pourquoi une propriété contiendrait un abonnement à un événement. –

Répondre

23

J'ai juste eu ce problème aussi, et l'ai résolu en enveloppant la ligne accédant au contrôle nul dans une vérification nulle. Cela semble être un peu une solution de contournement. Je pense que WPF essaie d'être utile ici en appelant notre événement Checked pendant InitializeComponent(), afin de s'assurer que toute logique UI (par exemple afficher/masquer des composants connexes) est exécutée en fonction de l'état initial de la case à cocher . J'ai testé avoir coché la case par défaut, et le gestionnaire d'événements n'est pas appelé, même si je l'ai câblé à la fois les événements Checked et Unchecked. Je l'ai même reproduit dans un projet WPF vide avec une seule case à cocher sur l'écran, et il se comporte de la même manière.

Le problème avec ce comportement par défaut est évidemment que certains des autres composants ne sont pas encore initialisés. Je pense que WPF doit attendre que tous les composants soient initialisés avant de déclencher l'événement Checked par défaut.Cela peut ne pas être considéré comme un bogue, mais je vais quand même ajouter une note à la page MSDN correspondante ...

0

L'un des contrôles utilise-t-il une liaison de données bidirectionnelle? J'ai rencontré ce problème où j'ai eu des zones de texte liées à une propriété sur un ViewModel. L'initialisation ViewModel déclenchait INotifyPropertyChanged jusqu'au contrôle lié, ce qui provoquait le déclenchement de l'événement TextChanged de la zone de texte. Ma solution de contournement à court terme consistait à déplacer l'abonnement à l'événement Window Loaded, mais comme vous le dites, c'est plutôt pénible. J'ai besoin de refactoriser le code pour changer l'ordre dans lequel mes objets sont initialisés, de sorte que les vues WPF (c'est-à-dire les fenêtres et les contrôles utilisateur) sont créées avant les ViewModels. Ensuite, je serai en mesure de déplacer l'enregistrement du gestionnaire d'événements dans XAML.

+0

Je n'utilise aucune liaison de données de compilation. – rediVider

4

Vous devriez être en mesure de vérifier les propriétés IsInitialized ou IsLoaded sur votre fenêtre pour vérifier si l'initialisation/chargement est terminé. Sinon, vous devrez vérifier null ou ajouter vos abonnements d'événement dans votre code derrière (après InitializeComponent).

De même, vous pourrez peut-être ajuster la façon dont vous accédez aux éléments. Par exemple, si vous avez quelque chose comme:

<ListBox x:Name="listBox" SelectionChanged="OnListBoxSelectionChanged" /> 

Puis dans votre code derrière vous pouvez obtenir la zone de liste de plusieurs façons:

private void OnListBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { 
    ListBox lb = this.listBox; // May be null 
    ListBox lb = sender as ListBox; // Should never be null 
    ListBox lb = e.Source as ListBox; // Same as sender in this case 
    ListBox lb = e.OriginalSource as ListBox; // Always the element that started the event (if handler is not attached directly to ListBox). 
    // ... Do Something ... 
} 
+0

J'ai un formulaire occupé avec constante en/dis-abling. Je devine que je devrais déplacer les abonnements d'événement au constructeur après les exécutions d'initialisation. – rediVider

5

Ce fut l'événement vérifié sur un bouton radio. Quand j'ai enlevé Checked = "true" du xaml, le problème est parti. (bien qu'il soit vérifié quand la fenêtre commence). Pas sûr de ce qui se passe ici, mais au moins je n'ai pas eu besoin de changer quoi que ce soit de majeur pour le réparer ... pour le moment.

+0

Merci rediVider, votre solution a fonctionné pour moi (j'utilisais .NET 4.5.1). –

0

Le contrôle de fenêtre déclenche les événements vérifiés lors de l'initialisation des sous-contrôles qui peuvent être vérifiés et sont mis à cocher comme initiale valeur.

Je suis fortement d'avis que c'est un bug. Juste le fait qu'il déclenche une exception NullReferenceException à partir de l'intérieur de l'assembly MFC devrait être suffisant pour s'attendre à un comportement inattendu. Considérant que l'éditeur Xaml crée des fonctions de gestionnaire dans votre classe partielle Control et que si cette classe n'est pas terminée, elle ne peut pas gérer les événements. Je ne pense pas que déclencher un événement coché pour un contrôle de votre paramètre initialisé à vérifié semble juste du tout.

Je veux dire, devrait-il déclencher un événement non coché si vous définissez son état initial sur non cochée?

1

J'ai eu le même problème et je pense que c'est un bug. J'ai trouvé une solution de contournement: J'ai enlevé le 'Ischecked' de Xaml et l'ai mis dans le code derrière l'init

Questions connexes