2014-05-14 58 views
2

我正在爲Windows窗體編寫大量單元測試,並且至今已經能夠弄清楚如何設置私有控件的屬性並調用其方法,反射。但我堅持如何將內聯lambda關聯到其中一個控件上發生的事件,在這種情況下是DataGridView的DataSourceChanged事件。我如何將匿名操作綁定爲使用反射的新事件處理程序

public static void ObserveGrid(this Form form, string controlName, Action action) 
{ 
    var controls = form.Controls.Find(controlName, true); 
    if (controls.Any()) 
    { 
     var control = controls[0] as DataGridView; 
     if (control != null) 
     { 
      EventInfo ei = typeof(DataGridView).GetEvent("DataSourceChanged"); 
      if (ei != null) 
      { 
       ei.AddEventHandler(control, Delegate.CreateDelegate(ei.EventHandlerType, control, action.Method)); 
      } 
     } 
    } 
} 

我希望能這樣稱呼它:

var monitor = new Mutex(); 
form.ObserveGrid("dataGridView1", 
    () => 
    { 
     Trace.WriteLine("Releasing mutex."); 
     monitor.ReleaseMutex(); 
    }); 
var sw = new Stopwatch(); 
form.ClickButton("btnSearch", sw); 
monitor.WaitOne(); 
sw.Stop(); 

在執行過程中,我得到了一個錯誤:

Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

我是什麼在這種情況下做錯了什麼?

UPDATE:

使用this偉大的職位,我已經改變了我的擴展類,像這樣:

public static void ObserveGrid(this Form form, string controlName, Action<object,object> action) 
    { 
     var controls = form.Controls.Find(controlName, true); 
     if (controls.Any()) 
     { 
      var control = controls[0] as DataGridView; 
      if (control != null) 
      { 
       EventInfo ei = typeof(DataGridView).GetEvent("DataSourceChanged"); 
       if (ei != null) 
       { 
        Delegate handler = ConvertDelegate(action, ei.EventHandlerType); 
        ei.AddEventHandler(control, handler); 
       } 
      } 
     } 
    } 

    public static Delegate ConvertDelegate(Delegate originalDelegate, Type targetDelegateType) 
    { 
     return Delegate.CreateDelegate(
      targetDelegateType, 
      originalDelegate.Target, 
      originalDelegate.Method); 
    } 

但是我得到的另一個錯誤,這一次有關從非同步釋放互斥螺紋:

Releasing mutex. System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ----> System.ApplicationException : Object synchronization method was called from an unsynchronized block of code.

更新2

爲SemaphoreSlim交換互斥鎖解決了同步問題。

回答

1

這裏是我落得這樣做:

首先,擴展類:現在

public static class Extensions 
{ 
    #region Public Methods and Operators 

    public static Stopwatch ClickButton(this Form form, string controlName) 
    { 
     var controls = form.Controls.Find(controlName, true); 
     if (controls.Any()) 
     { 
      var control = controls[0] as Button; 
      if (control != null) 
      { 
       MethodInfo mi = typeof(Button).GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance); 
       var stopWatch = Stopwatch.StartNew(); 
       mi.Invoke(
        control, 
        new object[] 
        { 
         EventArgs.Empty 
        }); 
       return stopWatch; 
      } 
     } 
     throw new ApplicationException("Control not found or of invalid Type"); 
    } 

    public static Delegate ConvertDelegate(Delegate originalDelegate, Type targetDelegateType) 
    { 
     return Delegate.CreateDelegate(targetDelegateType, originalDelegate.Target, originalDelegate.Method); 
    } 

    public static object GetControlProperty<T>(this Form form, string controlName, string propertyName) where T : class 
    { 
     var controls = form.Controls.Find(controlName, true); 
     if (controls.Any()) 
     { 
      var control = controls[0]; 
      PropertyInfo pi = typeof(T).GetProperty(propertyName); 
      return pi.GetValue(control, null); 
     } 
     throw new ApplicationException("Control not found or of invalid Type"); 
    } 

    public static void ObserveControlEvents<T>(this Form form, string controlName, string eventName, Action<object, object> action) where T : class 
    { 
     var controls = form.Controls.Find(controlName, true); 
     if (controls.Any()) 
     { 
      var control = controls[0] as T; 
      if (control != null) 
      { 
       EventInfo ei = typeof(T).GetEvent(eventName); 
       if (ei != null) 
       { 
        Delegate handler = ConvertDelegate(action, ei.EventHandlerType); 
        ei.AddEventHandler(control, handler); 
       } 
      } 
     } 
    } 

    public static void ObserveGrid(this Form form, string controlName, string eventName, Action<object, object> action) 
    { 
     var controls = form.Controls.Find(controlName, true); 
     if (controls.Any()) 
     { 
      var control = controls[0] as DataGridView; 
      if (control != null) 
      { 
       EventInfo ei = typeof(DataGridView).GetEvent(eventName); 
       if (ei != null) 
       { 
        Delegate handler = ConvertDelegate(action, ei.EventHandlerType); 
        ei.AddEventHandler(control, handler); 
       } 
      } 
     } 
    } 

    public static void SetControlProperty<T>(this Form form, string controlName, string propertyName, object value) where T : class 
    { 
     var controls = form.Controls.Find(controlName, true); 
     if (controls.Any()) 
     { 
      var control = controls[0]; 
      PropertyInfo pi = typeof(T).GetProperty(propertyName); 
      pi.SetValue(control, value, null); 
     } 
    } 

    public static void SetFormProperty(this Form form, string controlName, object value) 
    { 
     var controls = form.Controls.Find(controlName, true); 
     if (controls.Any()) 
     { 
      var control = controls[0]; 
      PropertyInfo pi = typeof(Control).GetProperty("Text"); 
      pi.SetValue(control, value, null); 
     } 
    } 

    #endregion 
} 

,在我的單元測試,我可以創建表格,設定值,觸發和觀察的事件:

[TestFixture] 
public class FormsTests 
{ 
    #region Public Methods and Operators 

    [TestCase(null, null, null, 1000)] 
    [TestCase("Kim", null, null, 500)] 
    [TestCase("Kim", null, "Akers", 250)] 
    [TestCase("Kim", "B", "Abercrombie", 100)] 
    public void InsuredSearcherResponseTimeWithReflectionTest(string firstName, string middleName, string lastName, long milliseconds) 
    { 
     var monitor = new SemaphoreSlim(1); 
     monitor.Wait(); 
     var form = new Insured(); 
     form.SetControlProperty<TextBox>("tbFirstName", "Text", firstName); 
     form.SetControlProperty<TextBox>("tbMiddleName", "Text", middleName); 
     form.SetControlProperty<TextBox>("tbLastName", "Text", lastName); 
     form.ObserveControlEvents<DataGridView>(
      "dataGridView1", 
      "DataSourceChanged", 
      (sender, args) => 
      { 
       Trace.WriteLine("Occured in delegate"); 
       monitor.Release(); 
      }); 
     Trace.WriteLine("Executing"); 
     var sw = form.ClickButton("btnSearch"); 
     monitor.Wait(); 
     sw.Stop(); 
     Trace.WriteLine(String.Format("Row count was {0} took {1}ms to process", form.GetControlProperty<DataGridView>("dataGridView1", "RowCount"), sw.ElapsedMilliseconds)); 
     Assert.IsTrue(sw.ElapsedMilliseconds < milliseconds); 
    } 

    [TestFixtureSetUp] 
    public void TestFixtureSetup() 
    { 
     var monitor = new SemaphoreSlim(1); 
     monitor.Wait(); 
     var form = new Insured(); 
     form.ObserveControlEvents<DataGridView>(
      "dataGridView1", 
      "DataSourceChanged", 
      (sender, args) => 
      { 
       Trace.WriteLine("Occured in delegate"); 
       monitor.Release(); 
      }); 
     form.ClickButton("btnSearch"); 
     monitor.Wait(); 
    } 
} 

我希望這可以幫助別人。

相關問題