我正在为Windows Forms编写一些单元测试,到目前为止我们已经能够弄清楚如何设置私有控件'使用Reflection,调用属性并调用它们的方法。但我仍然坚持如何关联内联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();
执行期间我收到错误:
无法绑定到目标方法,因为它的签名或安全性 透明度与委托类型的透明度不兼容。
在这种情况下,我做错了什么?
更新
使用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);
}
但是我得到了另一个错误,这次是关于从非同步线程中释放互斥锁:
释放互斥锁。 System.Reflection.TargetInvocationException: 调用的目标抛出了异常。 ----&GT; System.ApplicationException: 从不同步的代码块调用对象同步方法。
更新2
交换SemaphoreSlim的Mutex解决了同步问题。
答案 0 :(得分:1)
这是我最终做的事情:
首先,Extensions类:
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();
}
}
我希望这对某人也有帮助。
答案 1 :(得分:0)
尝试以下定义:
public static class Xtd
{
public static void AddEventEasy(this object component, EventInfo eventInfo, Delegate eventAction)
{
Delegate ConvertDelegate(Delegate originalDelegate, Type targetDelegateType)
{
return Delegate.CreateDelegate(
targetDelegateType,
originalDelegate.Target,
originalDelegate.Method);
}
eventInfo.AddEventHandler(component, ConvertDelegate(eventAction, eventInfo.EventHandlerType));
}
}