为什么没有设置滚动所有者
本文关键字:滚动 所有者 设置 为什么 | 更新日期: 2023-09-27 17:51:05
我开发测试驱动并想要测试,我的控件实现IScrollInfo
返回正确的ScrollViewer。此外,我想测试我的控件是否在 ScrollOwner 上调用了 InvalidateScrollInfo
。
控件如下所示:
private class MyControl : UserControl, IScrollInfo
{
public ScrollViewer ScrollOwner { get; set; }
... other code to implement IScrollInfo
}
我的测试(nunit(如下所示:
[Test]
public void Should_be_scrollable()
{
var ControlToTest = new MyControl();
var scrollViewer = new ScrollViewer { Content = ControlToTest };
var window = new Window { Content = scrollViewer };
window.Show();
Assert.That(ControlToTest, Is.InstanceOf<IScrollInfo>());
Assert.That(ControlToTest.ScrollOwner, Is.SameAs(scrollViewer));
}
但不幸的是,Assert.That(ControlToTest.ScrollOwner, Is.SameAs(scrollViewer));
失败了,因为ScrollOwner
null
。
问题 为什么ControlToTest.ScrollOwner
为空?
做了什么:我查看了ScrollOwner的设置位置。这发生在ScrollContentPresenter
的HookupScrollingComponents
中,而OnApplyTemplate
又被称为。据我了解,模板是在测量元素时应用的。这应该在显示窗口时完成。即使我window.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Render);
添加到表单中:
[Test]
public void Should_be_scrollable()
{
var scrollViewer = new ScrollViewer { Content = ControlToTest };
var window = new Window { Content = scrollViewer };
window.Show();
window.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Render);
Assert.That(ControlToTest, Is.InstanceOf<IScrollInfo>());
Assert.That(ControlToTest.ScrollOwner, Is.SameAs(scrollViewer));
}
它没有帮助。ScrollOwner
仍然null
.为什么?
奖励问题:如何测试InvalidateScrollInfo()
是否在scrollViewer
上被调用?
CanContentScroll
设置为 true
。
比测试有效:
[Test]
public void Should_be_scrollable()
{
var ControlToTest = new MyControl();
var scrollViewer = new ScrollViewer
{
Content = ControlToTest,
CanContentScroll = true
};
var window = new Window { Content = scrollViewer };
window.Show();
Assert.That(ControlToTest, Is.InstanceOf<IScrollInfo>());
Assert.That(ControlToTest.ScrollOwner, Is.SameAs(scrollViewer));
}
现在可以使用ControlToTest.ScrollOwner
进行进一步的测试。
奖励问题的答案:当您将ControlToTest.ViewportHeight
更改为小于测试中的ControlToTest.ExtentHeight
时,您可以检查 ControlToTest.ScrollOwner.ComputedVerticalScrollBarVisibility
属性以断言调用了ScrollOwner.InvalidateScrollInfo()
。这可能如下所示:
var scrollViewer = new ScrollViewer
{
Content = ControlToTest,
CanContentScroll = true,
VerticalScrollBarVisibility = ScrollBarVisibility.Auto
};
var window = new Window { Content = scrollViewer, Height = 600 };
window.Show();
Assert.That(
ControlToTest.ScrollOwner.ComputedVerticalScrollBarVisibility,
Is.EqualTo(Visibility.Collapsed));
window.Height = 300;
Render();
Assert.That(
ControlToTest.ScrollOwner.ComputedVerticalScrollBarVisibility,
Is.EqualTo(Visibility.Visible));
跟
private void Render()
{
ControlToTest.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);
}
很棘手,WPF 中发生的情况是,操作排队到调度程序上,并且仅在 UI 线程空闲后执行。所以很多窗口后的初始化。Show(( 不会发生,直到您释放 UI 的线程以执行其绑定/初始化,并将任务调度到优先级非常低的调度程序上,该调度程序将执行断言。这在单元测试中可能非常棘手。