2010-03-29 16 views
4

Ok, je ne voulais pas beaucoup d'ICommands dans mes MVVM ViewModels donc j'ai décidé de créer une MarkupExtension pour WPF que vous lui fournissez une chaîne (le nom de la méthode), et ça vous renvoie un ICommand qui exécute la méthode.Récupère la valeur d'une liaison WPF

est ici un extrait:

public class MethodCall : MarkupExtension 
{ 
    public MethodCall(string methodName) 
    { 
    MethodName = methodName; 
    CanExecute = "Can" + methodName; 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
    Binding bin= new Binding { Converter = new MethodConverter(MethodName,CanExecute) }; 

    return bin.ProvideValue(serviceProvider); 
    } 
} 

public class MethodConverter : IValueConverter 
{ 
    string MethodName; 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
    //Convert to ICommand 
    ICommand cmd = ConvertToICommand(); 
    if (cmd == null) 
     Debug.WriteLine(string.Format("Could not bind to method 'MyMethod' on object",MethodName)); 
    return cmd;  
    } 
} 

Il fonctionne très bien, sauf quand la liaison échoue (. Par exemple faute de frappe).

Lorsque vous faites cela dans xaml: {Binding MyPropertyName} vous voyez dans la fenêtre de sortie chaque fois que la liaison échoue. et elle vous indique le nom de propriété, le nom du type, etc.

La classe MethodConverter peut vous indiquer le nom de la méthode qui a échoué, mais elle ne peut pas vous indiquer le type d'objet source. Parce que la valeur sera nulle.

Je ne peux pas comprendre comment stocker le type d'objet source ainsi pour la classe suivante

public class MyClass 
{ 
    public void MyMethod() 
    { 
    } 
} 

et XAML suivant:

<Button Command={d:MethodCall MyMethod}>My Method</Button> 

Il dit actuellement:

"Could not bind to method 'MyMethod' on object 

mais je voudrais qu'il dise:

"Could not bind to method 'MyMethod' on object MyClass 

Des idées?

Répondre

1

Hmm, eh bien, je peux penser à un moyen détourné. Il peut y avoir quelque chose de plus facile/plus propre, mais essayez ceci:

  1. Obtenez la mise en œuvre IProvideValueTarget via le IServiceProvider.
  2. Utilisez les informations sur la cible pour résoudre un BindingExpression pour la propriété liée. Utilisez la propriété DataItem sur le BindingExpression pour obtenir l'objet source.

Quelque chose comme:

var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); 
var bindingExpression = BindingOperations.GetBindingExpression(provideValueTarget.TargetObject, (DependencyProperty)provideValueTarget.TargetProperty); 
var source = bindingExpression.DataItem; 

Awful, mais il devrait fonctionner. Il peut très bien y avoir un service qui fait cela pour vous, mais je ne pouvais pas trouver un après un coup d'oeil rapide dans MSDN.

0

Ce n'est pas une liaison, et pour les commandes, vous n'avez pas besoin de liaisons car les objets de commande ont un événement CanExecuteChanged.

public override object ProvideValue(IServiceProvider serviceProvider) 
{  
    ICommand cmd = ConvertToICommand(); 
    return cmd; 
} 

assurez-vous que ConverTOICommand retourne toujours quelque chose. Il est temps de penser à une commande null, ou quelque chose.