WPF MultiBinding échoue. Pourquoi?

J’ai ce balisage:

           

Dans le code derrière, j’ai cette ligne dans la méthode window_loaded:

 DataContext = uiManager; 

uiManager est de type UIManager et possède deux propriétés publiques nommées IsConnected et IsLoggedIn.

Ce code échoue au démarrage car le tableau de valeurs appelé dans le convertisseur par Multibinding n’est pas rempli de booléens, mais contient la valeur DependencyProperty.UnsetValue.

Lorsque j’utilise le balisage ci-dessous (et que je change le type de retour du convertisseur), cela fonctionne.

         

Il semble que la liaison définie via le DataContext dans le code derrière échoue dans le premier exemple, mais fonctionne dans le second. Pourquoi?

Pour être complet en dessous de la classe UIManager:

 public class UIManager:IUIManager { #region Implementation of IUIManager private const ssortingng IsLoggedInProperty = "IsLoggedIn"; private bool loggedIn; private readonly object loggedInLock = new object(); public bool IsLoggedIn { get { lock (loggedInLock) { return loggedIn; } } set { lock (loggedInLock) { if(value==loggedIn)return; loggedIn = value; OnPropertyChanged(IsLoggedInProperty); } } } private void OnPropertyChanged(ssortingng property) { if(PropertyChanged!=null)PropertyChanged(this,new PropertyChangedEventArgs(property)); } private const ssortingng IsConnectedProperty = "IsConnected"; private bool isConnected; private object isConnectedLock = new object(); public bool IsConnected { get { lock (isConnectedLock) { return isConnected; } } set { lock (isConnectedLock) { if(value==isConnected)return; isConnected = value; OnPropertyChanged(IsConnectedProperty); } } } #endregion #region Implementation of INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; #endregion } 

EDIT: La méthode de conversion pour le XAML défaillant (il échoue lors de la conversion en booléen de valeurs [0]:

 public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { var is_connected = (bool) values[0]; var is_loggedin = (bool) values[1]; return is_loggedin ? is_connected ? Colors.YellowGreen : Colors.Red : Colors.Gray; } 

pour le XAML de travail:

 public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { var is_connected = (bool) values[0]; var is_loggedin = (bool) values[1]; return is_loggedin ? is_connected ? Brushes.YellowGreen : Brushes.Red : Brushes.Gray; } 

Le problème n’a rien à voir avec un MultiBinding ou votre convertisseur. DependencyProperty.UnsetValue signifie que la liaison n’a aucune valeur. Et en effet, si vous exécutez en mode débogage, vous pouvez voir les erreurs de liaison dans la fenêtre de Output :

 System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsConnected; DataItem=null; target element is 'SolidColorBrush' (HashCode=17654054); target property is 'Color' (type 'Color') System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsLoggedIn; DataItem=null; target element is 'SolidColorBrush' (HashCode=17654054); target property is 'Color' (type 'Color') 

Alors simplifions un peu le balisage et appliquons quelques diagnostics:

          

L’application de la propriété de dépendance attachée PresentationTraceSources.TraceLevel génère une sortie supplémentaire:

 System.Windows.Data Warning: 52 : Created BindingExpression (hash=17654054) for Binding (hash=44624228) System.Windows.Data Warning: 54 : Path: 'GroupColor' System.Windows.Data Warning: 56 : BindingExpression (hash=17654054): Default mode resolved to OneWay System.Windows.Data Warning: 57 : BindingExpression (hash=17654054): Default update sortinggger resolved to PropertyChanged System.Windows.Data Warning: 58 : BindingExpression (hash=17654054): Attach to System.Windows.Media.SolidColorBrush.Color (hash=52727599) System.Windows.Data Warning: 60 : BindingExpression (hash=17654054): Use Framework mentor  System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found System.Windows.Data Warning: 61 : BindingExpression (hash=17654054): Resolve source deferred System.Windows.Data Warning: 91 : BindingExpression (hash=17654054): Got InheritanceContextChanged event from SolidColorBrush (hash=52727599) System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source System.Windows.Data Warning: 66 : BindingExpression (hash=17654054): Found data context element: GroupBox (hash=51393439) (OK) System.Windows.Data Warning: 67 : BindingExpression (hash=17654054): DataContext is null System.Windows.Data Warning: 91 : BindingExpression (hash=17654054): Got InheritanceContextChanged event from SolidColorBrush (hash=52727599) System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source (last chance) System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=GroupColor; DataItem=null; target element is 'SolidColorBrush' (HashCode=52727599); target property is 'Color' (type 'Color') 

Nous voyons que la liaison ne trouve pas un DataContext et que la liaison échoue. Lorsque je modifie le constructeur de la fenêtre de sorte que DataContext soit défini avant l’initialisation du contenu, la liaison fonctionne:

 public Window1() { DataContext = ...; InitializeComponent(); } 

Ce qui est étrange, car pour les reliures ailleurs, cela n’a pas d’importance. Vous ne savez pas pourquoi cela ne fonctionne pas là-bas, je ne peux donc que proposer des solutions de contournement. Ce qui fonctionne par exemple, c’est de créer le pinceau en tant que ressource avec les liaisons (cette ressource peut également être locale à GroupBox ):

             

Je suggérerais cependant de supprimer MultiBinding et de faire un traitement préalable dans le DataContext si votre classe UIManager est une sorte de MVVM ViewModel .

Ma théorie La couleur est struct (ne peut pas être null), donc SolidColorBrush.Color = null est incorrect. WPF ne peut pas créer SolidColorBrush et vous obtenez une exception.

            

BorderBrush est object (peut être null), donc GroupBox.BorderBrush = null est OK.

        

Ce SolidColorBrush n’est pas un object mais un FACTORY. Il n’est instancié que lorsque cela est nécessaire et vous avez déjà attaché DataContext.

            

Juste mes 2 cents.

Lisez mon article, d’ailleurs, pourrait être utile si vous avez besoin de liens étranges ou d’animations avec des convertisseurs étranges. http://www.codeproject.com/KB/WPF/BindingHub.aspx

C’est pour des raisons comme celle-ci que vous voudrez peut-être envisager l’apprentissage de MVVM. Ce modèle vous aide à résumer le modèle et les liaisons de manière à ne pas trop compter sur les PDD; vous pouvez simplement vous lier à une propriété à notifier dans un modèle de vue.

Il existe plusieurs excellents articles sur MVVM, je vous suggère donc de commencer par lire les œuvres de Karl Shifflett, Josh Smith, Marlon Grech et Sacha Barber.