Метод вызова MVVM в представлении (из ControlTemplate через ViewModel) - PullRequest
0 голосов
/ 13 ноября 2010

Хотелось бы узнать, как можно решить следующую проблему БЕЗ использования агрегации событий.Это для WPF 3.5 с пакетом обновления 1 (SP1), поэтому CallMethodBehavior недоступен.

Простой сценарий: щелчок по кнопке внутри шаблона ControlTemplate должен быть запущен на виртуальной машине.Я использовал ActionMessage CaliburnMicro, который работал нормально.Внутри ViewModel я хочу вызвать метод внутри View, который запускает только пользовательский переход (без реальной логики).Я перепробовал много вещей, но у меня ничего не вышло.

Я создал свойство в своем представлении, которое могло бы вызвать метод, но я не могу использовать триггеры, чтобы установить новое значение для свойства, потому что яя не могу сказать установщику, что нужно нацелить свойство за пределами элемента управления.

Поэтому, по сути, я хочу обновить свойство в viewmodel и вызвать set-свойство в классе представления.Или, если у вас есть идеи, как вообще обойти это: я открыт для новых идей!: D

С уважением, Гопе

Ответы [ 2 ]

1 голос
/ 15 ноября 2010

я думаю, что самый простой способ - выставить событие с вашего виртуального компьютера и подписаться на него, на ваш взгляд?я использовал это для диалогов, чтобы отправить DialogResult из VM

0 голосов
/ 16 ноября 2010

Я нашел решение, с которым я могу жить: я перенес действие CallMethodAction на 3.5 и написал свой собственный PropertyChangedTrigger.Довольно просто вызвать метод внутри представления через PropertyChange в viewmodel - Дети: не пытайтесь делать это дома.Это только для особых сценариев!: D

Найдите мой код ниже:

использование:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

<i:Interaction.Triggers >         
    <Framework:PropertyChangedTrigger Binding="{Binding StartTransition}" Value="True">
        <Framework:CallMethodAction MethodName="ApplyTransition" />
    </Framework:PropertyChangedTrigger>
</i:Interaction.Triggers>

PropertyChangedTrigger:

public class PropertyChangedTrigger : TriggerBase<DependencyObject>
{
    public static readonly DependencyProperty BindingProperty = DependencyProperty.Register("Binding", typeof(object), typeof(PropertyChangedTrigger), new PropertyMetadata(new PropertyChangedCallback(OnBindingChanged)));
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(PropertyChangedTrigger), new PropertyMetadata(null));

    public object Binding
    {
        get
        {
            return base.GetValue(BindingProperty);
        }
        set
        {
            base.SetValue(BindingProperty, value);
        }
    }

    public object Value
    {
        get
        {
            return base.GetValue(ValueProperty);
        }
        set
        {
            base.SetValue(ValueProperty, value);
        }
    }

    protected virtual void EvaluateBindingChange(object args)
    {
        var propertyChangedArgs = (DependencyPropertyChangedEventArgs)args;
        string newValue = propertyChangedArgs.NewValue.ToString();
        bool equal = string.Equals(newValue, Value.ToString(),StringComparison.InvariantCultureIgnoreCase);
        if(equal)
        {
            InvokeActions(args);
        }
    }

    private static void OnBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        ((PropertyChangedTrigger)sender).EvaluateBindingChange(args);
    }
}

CallMethodAction:

 public class CallMethodAction : TargetedTriggerAction<FrameworkElement>
{
    private List<MethodDescriptor> methodDescriptors = new List<MethodDescriptor>();
    public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register("MethodName", typeof(string), typeof(CallMethodAction), new PropertyMetadata(new PropertyChangedCallback(OnMethodNameChanged)));
    public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register("TargetObject", typeof(object), typeof(CallMethodAction), new PropertyMetadata(new PropertyChangedCallback(OnTargetObjectChanged)));

    protected override void OnAttached()
    {
        base.OnAttached();
        this.UpdateMethodInfo();
    }

    protected override void OnDetaching()
    {
        this.methodDescriptors.Clear();
        base.OnDetaching();
    }

    private static void OnMethodNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        ((CallMethodAction)sender).UpdateMethodInfo();
    }

    private static void OnTargetObjectChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        ((CallMethodAction)sender).UpdateMethodInfo();
    }

    private static bool AreMethodParamsValid(ParameterInfo[] methodParams)
    {
        if (methodParams.Length == 2)
        {
            if (methodParams[0].ParameterType != typeof(object))
            {
                return false;
            }
            if (!typeof(EventArgs).IsAssignableFrom(methodParams[1].ParameterType))
            {
                return false;
            }
        }
        else if (methodParams.Length != 0)
        {
            return false;
        }
        return true;
    }

    protected override void Invoke(object parameter)
    {
        if (base.AssociatedObject != null)
        {
            MethodDescriptor descriptor = this.FindBestMethod(parameter);
            if (descriptor != null)
            {
                ParameterInfo[] parameters = descriptor.Parameters;
                if (parameters.Length == 0)
                {
                    descriptor.MethodInfo.Invoke(this.Target, null);
                }
                else if ((((parameters.Length == 2) && (base.AssociatedObject != null)) && ((parameter != null) && parameters[0].ParameterType.IsAssignableFrom(base.AssociatedObject.GetType()))) && parameters[1].ParameterType.IsAssignableFrom(parameter.GetType()))
                {
                    descriptor.MethodInfo.Invoke(this.Target, new object[] { base.AssociatedObject, parameter });
                }
            }
            else if (this.TargetObject != null)
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "No valid method found.", new object[] { this.MethodName, this.TargetObject.GetType().Name }));
            }
        }
    }

    private MethodDescriptor FindBestMethod(object parameter)
    {
        if (parameter != null)
        {
            parameter.GetType();
        }
        return this.methodDescriptors.FirstOrDefault(methodDescriptor => (!methodDescriptor.HasParameters || ((parameter != null) && methodDescriptor.SecondParameterType.IsAssignableFrom(parameter.GetType()))));
    }

    private void UpdateMethodInfo()
    {
        this.methodDescriptors.Clear();
        if ((this.Target != null) && !string.IsNullOrEmpty(this.MethodName))
        {
            foreach (MethodInfo info in this.Target.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance))
            {
                if (this.IsMethodValid(info))
                {
                    ParameterInfo[] parameters = info.GetParameters();
                    if (AreMethodParamsValid(parameters))
                    {
                        this.methodDescriptors.Add(new MethodDescriptor(info, parameters));
                    }
                }
            }
            this.methodDescriptors = this.methodDescriptors.OrderByDescending<MethodDescriptor, int>(delegate(MethodDescriptor methodDescriptor)
            {
                int num = 0;
                if (methodDescriptor.HasParameters)
                {
                    for (Type type = methodDescriptor.SecondParameterType; type != typeof(EventArgs); type = type.BaseType)
                    {
                        num++;
                    }
                }
                return (methodDescriptor.ParameterCount + num);
            }).ToList<MethodDescriptor>();
        }
    }


    private bool IsMethodValid(MethodInfo method)
    {
        if (!string.Equals(method.Name, this.MethodName, StringComparison.Ordinal))
        {
            return false;
        }
        if (method.ReturnType != typeof(void))
        {
            return false;
        }
        return true;
    }

    public void InvokeInternal()
    {
        if (AssociatedObject != null)
        {
            foreach (
                MethodInfo info in AssociatedObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance))
            {
                if (IsMethodValid(info))
                {
                    info.Invoke(AssociatedObject, new object[0]);
                }
            }
        }
    }





    public string MethodName
    {
        get
        {
            return (string)base.GetValue(MethodNameProperty);
        }
        set
        {
            base.SetValue(MethodNameProperty, value);
        }
    }

    private object Target
    {
        get
        {
            return (TargetObject ?? base.AssociatedObject);
        }
    }

    public object TargetObject
    {
        get
        {
            return base.GetValue(TargetObjectProperty);
        }
        set
        {
            base.SetValue(TargetObjectProperty, value);
        }
    }





    private class MethodDescriptor
    {
        public MethodDescriptor(MethodInfo methodInfo, ParameterInfo[] methodParams)
        {
            MethodInfo = methodInfo;
            Parameters = methodParams;
        }

        public bool HasParameters
        {
            get
            {
                return (Parameters.Length > 0);
            }
        }

        public MethodInfo MethodInfo { get; private set; }

        public int ParameterCount
        {
            get
            {
                return Parameters.Length;
            }
        }

        public ParameterInfo[] Parameters { get; private set; }

        public Type SecondParameterType
        {
            get
            {
                if (Parameters.Length >= 2)
                {
                    return Parameters[1].ParameterType;
                }
                return null;
            }
        }
    }
}

Надеюсь, это поможет любому.Все вопросы приветствуются!Помните: все это можно найти в Expression Blend SDK 4. Этот код предназначен только для людей, которые вынуждены работать с более старыми версиями, такими как 3.5

С уважением Gope Gope

...