2010-11-13 46 views
0

我想知道如何在不使用事件聚合的情况下解决以下问题。这是针对WPF 3.5 SP1的,因此CallMethodBehavior不可用。查看MVVM调用方法(通过ViewModel从ControlTemplate)

简单场景:点击ControlTemplate中的按钮需要触发VM。我用CaliburnMicro的ActionMessage工作得很好。在ViewModel内部,我想在View中触发一个方法,它只启动一个自定义转换(没有真正的逻辑)。我尝试了很多东西,但我没有成功。

我在我的视图中创建了一个属性,它可以调用该方法,但我无法使用触发器为该属性设置一个新值,因为我无法告诉setter将控件模板以外的属性作为目标。

因此,本质上我想更新视图模型中的属性并触发视图类中的set-property。或者如果你有任何想法如何解决这个问题:我愿意接受新的想法! :d

问候 Gope

回答

0

我找到了一个解决方案,我可以住在一起发送的DialogResult:我移植了CallMethodAction 3.5,写我自己PropertyChangedTrigger。通过视图模型中的PropertyChange调用视图内的方法非常简单 - Kids:不要在家中尝试这种方法。这只适用于特殊情况! :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; 
      } 
     } 
    } 
} 

希望这有助于anybode。所有的问题都欢迎! Remeber:这一切都可以在Expression Blend中4 SDK中找到这段代码只对谁是被迫与旧版本的工作像3.5

问候 Gope Gope

+0

Hello Gope,我想用这段代码做测试。不幸的是它不完整。 FirtsOrDefault和OrderByDescending方法未在类MethodDescriptor中定义。你可以添加这个代码吗?编辑: 糟糕,methodDescriptor是类型列表,所以这种方法来自列表。使用System.Linq时丢失了 。 – 2011-05-26 12:16:11

1

我认为最简单的方法是从你的虚拟机暴露的事件和订阅它在你的看法? 我用this的对话从VM

+0

这的确是一个想法的人,但我尽量保持代码隐藏到最低限度。我不喜欢它的是,你不应该有任何对视图模型的引用,这意味着要抛出DataContext,我不喜欢这两种,但实际上你的建议会起作用并且很简单,这使得它变得迷人。 :D 我发现了另一个可能的解决方案,我在下面发表。 最好的问候和感谢您花时间回答我的问题! – Gope 2010-11-16 08:05:52