I develop test driven and want to test, that my control which implements IScrollInfo returns the correct ScrollViewer. Additionally I'd like to test that my control called InvalidateScrollInfo on the ScrollOwner.
The control looks like:
private class MyControl : UserControl, IScrollInfo
{
public ScrollViewer ScrollOwner { get; set; }
... other code to implement IScrollInfo
}
My test (nunit) looks like:
[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));
}
But unfortunately the Assert.That(ControlToTest.ScrollOwner, Is.SameAs(scrollViewer)); fails because the ScrollOwner is null.
Question Why is ControlToTest.ScrollOwner null?
What I did: I looked where the ScrollOwner gets set. This happens in the HookupScrollingComponents in the ScrollContentPresenter, which in turn is called in OnApplyTemplate. And for my understanding the template is applied when the element gets measured. And this should be done when the window is shown. Even when I added window.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Render); to form:
[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));
}
it didn't help. The ScrollOwner is still null. Why?
Bonus question: How do I test that InvalidateScrollInfo() was called on the scrollViewer?
It is neccessary, that the CanContentScroll is set to true.
Than the test works:
[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));
}
Now further tests with the ControlToTest.ScrollOwner can be performed.
Answer to Bonus question: when you change the ControlToTest.ViewportHeight to be smaller than the ControlToTest.ExtentHeight in the test, then you can check the ControlToTest.ScrollOwner.ComputedVerticalScrollBarVisibility property to assert that the ScrollOwner.InvalidateScrollInfo() was called. This might look like:
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));
with
private void Render()
{
ControlToTest.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With