Получить значение для привязки WPF - PullRequest
5 голосов
/ 29 марта 2010

Хорошо, я не хотел связку ICommands в моих MVVM ViewModels, поэтому я решил создать MarkupExtension для WPF, чтобы вы передавали ему строку (имя метода), и он возвращает вам ICommand, которая выполняется метод.

вот фрагмент:

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

Он отлично работает, за исключением случаев, когда не удается выполнить привязку (например, вы ошиблись).

Когда вы делаете это в xaml: {Binding MyPropertyName} вы видите в окне вывода всякий раз, когда привязка не выполняется. и он сообщает вам propertyName имя типа и т. д.

Класс MethodConverter может сообщить вам имя метода, который не удался, но не может сказать вам тип исходного объекта. Потому что значение будет нулевым.

Я не могу понять, как хранить исходный тип объекта, так что для следующего класса

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

и следующий xaml:

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

В настоящее время говорится:

"Could not bind to method 'MyMethod' on object

но я бы хотел сказать:

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

Есть идеи?

Ответы [ 2 ]

2 голосов
/ 29 марта 2010

Хм, ну, я могу придумать обходной путь. Там может быть что-то проще / чище, но попробуйте это:

  1. Получить реализацию IProvideValueTarget через IServiceProvider.
  2. Используйте целевую информацию для разрешения BindingExpression для связанного свойства.
  3. Используйте свойство DataItem в BindingExpression для получения исходного объекта.

Что-то вроде:

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

Ужасно, но это должно работать. Возможно, есть служба, которая сделает это за вас, но я не смог найти ее после быстрого просмотра в MSDN.

0 голосов
/ 22 апреля 2011

Это не привязка, и для команд вам не нужны привязки, потому что объекты команд имеют событие CanExecuteChanged.

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

убедитесь, что ConverTOICommand всегда что-то возвращает. Время подумать о нулевой команде или о чем-то.

...