2012-10-11 50 views
4

我有一個第三方庫的TargetedTriggerAction,想要調用/調用而不附加到按鈕。我沒有問題讓它與按鈕一起工作,但我想要做它以響應一些非UI事件。以編程方式調用WPF TargetedTriggerAction

這裏是行動的類聲明:

public class MeasureAction : TargetedTriggerAction<Map> 

這裏是我的設置代碼至今:

var measure = new MeasureAction(); 
    measure.TargetObject = _mapControl; 
    measure.MeasureMode = MeasureAction.Mode.Polyline; 
    measure.MapUnits = DistanceUnit.Miles; 

我希望能夠做這樣的事,但我知道調用被保護:

measure.Invoke(); 

回答

0

第三方類是否密封?

如果不是,「最好」的答案可能是從MeasureAction派生自己的班級,並添加一個調用者(如果要保持乾淨,請保持內部/受保護)。

如果它的密封/否則凍結,你最好的選擇可能是反思 - 有很多方法可以緩存/否則加速這個通話費用,但基本代碼將是這樣的:

// Paste in the code in the original question here, name of instance == measure 
var actionMethod = typeof(MeasureAction) 
    .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic) 
    .FirstOrDefault(meth => meth.Name == "Invoke"); 
if(actionMethod != null) 
{ 
    var result = actionMethod.Invoke(measure, null); 
} 
+0

它不是密封的內部地圖,但它內部的第三方圖書館。你有一些關於如何將調用者添加到派生類的示例代碼? –

+0

啊,如果它「內部正確」(即被標記爲內部類),它就和密封一樣好......沒有從我知道的內部類派生的乾淨方法。你可能會被反射路線困住。如果是這樣的話,有很多方法可以確保Reflection的命中是一次性命中;表達式樹,Delegate.CreateDelegate,緩存返回的方法信息等。 – JerKimball

+0

感謝迄今的答覆。如果我按照列出的方式運行它,則會出現TargetParameterCountException - 參數計數不匹配。所以我用這個語法添加了一個參數: object [] param = new object [1]; param [0] = _mapControl; var result = actionMethod。調用(measure,param); 但我仍然得到一個異常「異常已被調用的目標拋出」和(內部異常)「對象引用未設置爲對象的實例」。沒有一個對象(measure,param,param [0],_mapControl)爲空。 –

7

要調用你的觸發器動作,你需要一個觸發器!

namespace TriggerTest 
{ 
    using System.Windows; 

    /// <summary> 
    /// A trigger that may be invoked from code. 
    /// </summary> 
    public class ManualTrigger : System.Windows.Interactivity.TriggerBase<DependencyObject> 
    { 
     /// <summary> 
     /// Invokes the trigger's actions. 
     /// </summary> 
     /// <param name="parameter">The parameter value.</param> 
     public void Invoke(object parameter) 
     { 
      this.InvokeActions(parameter); 
     } 
    } 
} 

上面是一個觸發器實現,可以調用沒有任何UI依賴關係。例如:

var measure = new MeasureAction(); 
measure.TargetObject = _mapControl; 
measure.MeasureMode = MeasureAction.Mode.Polyline; 
measure.MapUnits = DistanceUnit.Miles; 

ManualTrigger trigger = new ManualTrigger(); 
trigger.Actions.Add(measure); 
trigger.Invoke(null); 

要調用這個更容易,你可以添加一個擴展方法TriggerAction

namespace TriggerTest 
{ 
    using System.Windows.Interactivity; 

    /// <summary> 
    /// Allows a trigger action to be invoked from code. 
    /// </summary> 
    public static class TriggerActionExtensions 
    { 
     /// <summary> 
     /// Invokes a <see cref="TriggerAction"/> with the specified parameter. 
     /// </summary> 
     /// <param name="action">The <see cref="TriggerAction"/>.</param> 
     /// <param name="parameter">The parameter value.</param> 
     public static void Invoke(this TriggerAction action, object parameter) 
     { 
      ManualTrigger trigger = new ManualTrigger(); 
      trigger.Actions.Add(action); 

      try 
      { 
       trigger.Invoke(parameter); 
      } 
      finally 
      { 
       trigger.Actions.Remove(action); 
      } 
     } 

     /// <summary> 
     /// Invokes a <see cref="TriggerAction"/>. 
     /// </summary> 
     /// <param name="action">The <see cref="TriggerAction"/>.</param> 
     public static void Invoke(this TriggerAction action) 
     { 
      action.Invoke(null); 
     } 
    } 
} 

現在你可以寫什麼你真的想要

var measure = new MeasureAction(); 
measure.TargetObject = _mapControl; 
measure.MeasureMode = MeasureAction.Mode.Polyline; 
measure.MapUnits = DistanceUnit.Miles; 
measure.Invoke(); 
+0

夢幻般的答案,這實質上是我所希望的,但它不工作。我收到一個異常:「對象引用未設置爲對象的實例」。看看細節,它看起來像在MeasureAction類中可能有一個私有變量,可能沒有被初始化。雖然不能確定。我可以在反射器中看到整個MeasureAction類。有什麼我可以尋找更好的診斷? –

+0

在這裏抓住吸管,但是在'MeasureAction'中是否有任何代碼依賴於'AssociatedObject'?也許你可以將它設置爲'_mapControl',以達到良好的效果。 – Olly

+1

由於您可以在調試器中看到內部結構,因此您可以嘗試在XAML中以傳統方式使用'MeasureAction'並檢查其屬性。也許用一個點擊處理程序創建一個按鈕並在那裏設置一個斷點。然後在你調用Invoke()之前將它與你的'measure'對象進行比較。有什麼不同? – Olly

0

老的文章,但可能會有幫助。我不喜歡這個

public class MyMeasureAction : MeasureAction 
{ 
    public void Execute() 
    { 
     OnTargetChanged(null, (Map)TargetObject); 
     Invoke(null); 
    } 
} 

...

var mymeasure = new MyMeasureAction(); 
mymeasure.TargetObject = MyMap; 
mymeasure.xxxx = xxxx 
.... 
mymeasure.Execute(); 

的OnTargetChanged()方法將初始化MeasureAction