WPF中的力约束
我正在编写测试来检查XAML中指定的WPF中的力约束,wpf,unit-testing,data-binding,Wpf,Unit Testing,Data Binding,我正在编写测试来检查XAML中指定的绑定元素的正确性。到目前为止,它们仍然有效,唯一的问题是我不知道如何正确地强制数据绑定。令人惊讶的是,仅仅在DataContext中设置某些内容是不够的,只有显示控件/窗口,绑定才会发生。请不要说我在写“单元测试”,我不想显示任何窗口 请看下面的代码: // This is main class in console application where I have all WPF references added public class Program {
绑定元素的正确性。到目前为止,它们仍然有效,唯一的问题是我不知道如何正确地强制数据绑定。令人惊讶的是,仅仅在DataContext
中设置某些内容是不够的,只有显示控件/窗口,绑定才会发生。请不要说我在写“单元测试”,我不想显示任何窗口
请看下面的代码:
// This is main class in console application where I have all WPF references added
public class Program
{
[STAThread]
public static void Main()
{
var view = new Window();
BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));
view.DataContext = new int[5];
//view.Show(); view.Close(); // <-- this is the code I'm trying not to write
Console.WriteLine(view.Title);
}
}
//这是控制台应用程序中的主类,我在其中添加了所有WPF引用
公共课程
{
[状态线程]
公共静态void Main()
{
var view=新窗口();
BindingOperations.SetBinding(视图,Window.TitleProperty,新绑定(“长度”);
view.DataContext=newint[5];
//view.Show();view.Close();//不确定,但类似的方法可能会奏效
view.GetBindingExpression(Window.TitleProperty).UpdateTarget();
我认为您应该首先设置DataContext,然后进行绑定,例如:
view.DataContext = new int[5];
BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));
我不确定这是否是一般问题的真正解决方案,但它在这种情况下有效。我不相信窗口的绑定会在不调用Show
或ShowDialog
的情况下运行,因为这是它与UI消息循环/调度程序关联的唯一方式
您最好将其设置为尽可能不可见,可能使用扩展方法来清理:
public static void PokeWindowDispatcher(this Window window)
{
window.WindowState = WindowState.Minimized;
window.ShowInTaskbar = false;
window.Visibility = Visibility.None;
using (var wait = new ManualResetEvent())
{
Action<object, RoutedEventArgs> loaded = (sender, e) => wait.Set();
window.Loaded += loaded;
try
{
window.Show();
wait.WaitOne();
}
finally
{
window.Loaded -= loaded;
window.Close();
}
}
}
公共静态void PokeWindowDispatcher(此窗口)
{
window.WindowState=WindowState.Minimized;
window.ShowInTaskbar=false;
window.Visibility=Visibility.None;
使用(var wait=new ManualResetEvent())
{
加载的操作=(发送方,e)=>wait.Set();
window.Loaded+=已加载;
尝试
{
window.Show();
等等,等等;
}
最后
{
window.Loaded-=已加载;
window.Close();
}
}
}
我也遇到了同样的问题,从六个变量中我得到了一个想法。非常简单。
我在WinForms应用程序中使用WPF,所以我使用ElementHost控件在WinForms控件上托管WPF控件。要强制WinForms控件初始化,您只需读取句柄的值(实际上是Windows HWND),这将强制控件完全初始化自身,包括子ElementHost和所有WPF绑定工作。
我没有尝试对纯Wpf控件执行相同的操作。但是您可以轻松地使用ElementHost初始化Wpf控件,如下所示:
var el = new ElementHost();
var p = new TextBlock();
p.DataContext = new { Data = "1234" };
p.SetBinding(TextBlock.TextProperty, "Data");
el.Child = p;
var t = el.Handle;
Debug.Assert(p.Text == "1234");
PS:发现,如果您先设置DataContext,然后才强制创建句柄(就像我的示例一样),那么一切都会更好。但是,我认为,对于您来说,这已经是一个问题了,所以应该不是一个问题。您是否尝试过使用IsDataBound
另外,请查看以下内容:
System.Windows.Interop.WindowInteropHelper helper=new System.Windows.Interop.WindowInteropHelper(view.EnsureHandle()
我的另一个问题是,为什么要对已经过技术测试的东西进行单元测试?顺便说一句,我不是在批评,只是想更好地理解一下。如果您试图测试您的观点的正确性,我建议您测试您的观点:-)
为什么不从单元测试运行UI并编写代码,在更改数据后检查UI的内容呢
VS2010确实有GUI测试,或者您可以查看Snoop等工具的代码
编辑以下评论:
如果您只想测试一些简单的绑定,请尝试编写一个静态代码测试,该测试使用XAMLs上的视图模型和正则表达式上的反射作为生成后事件运行。在VM上添加属性或使用配置文件,以便您的测试将知道哪个视图接收哪个视图模型作为DataContext。比较视图模型中的属性名称和类型如果字符串不匹配,则抛出异常(从而导致生成失败)
如果绑定更复杂(转换器、多绑定等),那么实现起来可能会更复杂一些。调度程序将使用DispatcherPriority.DataBind更新绑定-因此,如果您等待具有SystemIdle优先级的虚拟任务,则您可以确保任何挂起的数据绑定都已完成
try
{
this.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => { }));
}
catch
{
// Cannot perfom this while Dispatcher in suspended mode
}
这不会有帮助,因为在真实代码中,我不知道在视图上设置了哪些绑定,请参见我的更新。它可以工作,但我无法在真实代码中执行。在真实代码中(请参见我的第一次更新)我收到一个包含所有绑定的视图
。绑定是用XAML创建的,XAML作为构造函数中调用的InitializeComponents
的一部分进行解析,因此在设置绑定之前无法获取视图
。是否尝试调用View.UpdateLayout()或View.InvalidateVisual()?@Aaron,正在尝试,但没有帮助。@Snowbear您在标准WPF应用程序中尝试过这些不同的方法吗?@Snowbear测试视图是出了名的困难。为什么不在xUnit或您正在使用的任何测试框架中创建视图的实例,并根据将DataContext设置为g来验证控件是否具有预期值iven ViewModel?声明单元测试类似于控制台应用程序并不意味着什么……您正在测试视图,而不管您使用的是什么测试框架。@Snowbear如果您没有测试绑定中的值是否准确,那么您的测试范围很窄,您现在正在尝试测试.NET FW,这是没有意义的。B绑定可以在没有Show
的情况下工作,您可以检查Gimno的方法。使用他的代码绑定
可以工作,尽管我认为他的解决方案不适合我。您可以尝试使用Dispatcher.PushFrame()推送一个新的DispatcherFrame
,但我不相信如果没有为您的窗口制作HWND
,任何事情都会发生