2010-11-13 68 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