WPF Data Binding Testing Module

I am trying to use unit test my own WPF control using NUnit. The control is a ListView of buttons bound to a list (DataContext is configured in the control constructor).

I would like to write tests that (for example) add items to the list and verify that a new button is added to the view, etc. However, when I add an item to the list in my NUnit test, it still reports that the ListView is empty. Everything works fine when I run my application.

I have included the corresponding code below. What do I need to do to verify this?

XAML:

<ListView x:Class="SoundBlock" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" ItemsSource="{Binding Path=Sounds}"> <ListView.ItemTemplate> <DataTemplate> <Button Content="{Binding Title}" /> </DataTemplate> </ListView.ItemTemplate> </ListView> 

Class definition

 public partial class SoundBlock : ListView { public SoundBlock(Board xiBoard) { // Initialize. InitializeComponent(); // Set the data context for this block. DataContext = xiBoard; // Board has an ObservableCollection<Sound> // property called Sounds. } } 

Test case

 [Test] public void TestAddSound() { board = new Board(); block = new SoundBlock(board); Assert.AreEqual(0, block.Items.Count); sound = new Sound("sound.mp3"); board.Sounds.Add(sound); Assert.AreEqual(1, block.Items.Count); // This fails - count is still 0 } 
+6
source share
3 answers

See my question: Force binding in WPF

You must force bind, it will not work until control is shown. You can put it in a new window and show the window.

+4
source

I'm not sure what is happening and why this works, but if you use this small helper class to set the data context in the control you want to test, then it works.

 public class DataContextHelper { public static void InjectDataContext(object element, object dataContext) { if (dataContext == null) return; if (element is FrameworkContentElement) ((FrameworkContentElement)element).DataContext = dataContext; else if (element is FrameworkElement) ((FrameworkElement)element).DataContext = dataContext; TriggerUpdateOfInMemoryView(); } /// <summary> /// Triggers an update to a view that exists only in memory, not on the screen. /// </summary> /// <remarks> /// When setting data context or modifying the control tree of a view that exists in /// memory, then those changes are not automatically visible when eg attempting to /// print the view. This function will trigger the update of the view so, eg a print /// will display the updated view. /// </remarks> public static void TriggerUpdateOfInMemoryView() { var dispatcher = Dispatcher.CurrentDispatcher; dispatcher.Invoke( DispatcherPriority.SystemIdle, new DispatcherOperationCallback(arg => null), null); } } 
+3
source

Since you linked your ItemSource to the list so that any changes in the collection do not apply to the user interface control, since List does not implement INotifyCollectionChanged , and therefore, no changes will be displayed in the user interface.

Instead of List<Sound> you can use ObservableCollection<Sound> . ObservableCollection internally implements the INotifyCollectioChanged interface.

0
source

Source: https://habr.com/ru/post/901342/


All Articles