I’ve got the following combobox defined:
<ComboBox x:Name="cmbCurrency"
ItemsSource="{Binding IsoCurrenciesList}"
DisplayMemberPath="Description"
SelectedValuePath="LocaleID"
SelectedValue="{Binding CurrencyId, Mode=TwoWay">
</ComboBox>
Where IsoCurrenciesList is an IEnumerable<IsoCurrency> – the type being defined by us and declared in the view model as:
private IEnumerable<IsoCurrency> isoCurrenciesList;
public IEnumerable<IsoCurrency> IsoCurrenciesList
{
get { return isoCurrenciesList; }
set
{
isoCurrenciesList = value;
RaisePropertyChangedEvent("IsoCurrenciesList");
}
}
My unit test creates an instance of the view and view model and sets up some dummy currency data in a local list:
[TestInitialize]
public void TestInit()
{
_target = new View();
_viewModel = new ViewModel();
var ukp = new IsoCurrency { Code = "GBP", Description = "Pound Sterling", LocaleID = 826 };
var usd = new IsoCurrency { Code = "USD", Description = "US Dollar", LocaleID = 840 };
var eur = new IsoCurrency { Code = "EUR", Description = "Euro", LocaleID = 978 };
_currencies = new List<IsoCurrency> { ukp, usd, eur };
GetUIElement<Grid>("LayoutRoot").DataContext = _viewModel;
}
private T GetUIElement<T>(string name) where T : UIElement
{
return (T)_target.FindName(name);
}
Then the test method is called. This should set the currency ComboBox.Items (via the ItemsSource property)
[Asynchronous]
[TestMethod]
public void TestCurrencySelection()
{
_target.Loaded += (s, e) =>
{
// Set the currency list explicitly
_viewModel.IsoCurrenciesList = _currencies;
var currencyCombo = GetUIElement<ComboBox>("cmbCurrency");
// This assert fails as Items.Count == 0
CollectionAssert.AreEquivalent(currencyCombo.Items, _currencies, "Failed to data-bind currencies.");
EnqueueTestComplete();
};
TestPanel.Children.Add(_target);
}
I’ve followed the guidelines on Jeremy Likeness’s blog but I can’t get the bindings test to pass.
I’ve tried testing the bindings of other properties – simple strings, booleans and integers but the changes made at either end aren’t reflected to the other.
The only thing I can think of is that there is another step I need to do after adding the view to the TestPanel to “activate” the bindings, but I’ve no idea what it could be.
UPDATE
I should point out that the code works fine in the actual application. Based on the comments (particularly those from Adam Sills) it looks like the problem lies in the code I haven’t posted – i.e. it’s something in the way we’ve structured the XAML or there’s a difference in the way we set the DataContext. At least I can concentrate my efforts in (hopefully) the right area.
It appears that the position of the control in the view does matter. The page XAML is something like this:
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
...
</VisualStateManager.VisualStateGroups>
<toolkit:BusyIndicator x:Name="activityControl"
IsBusy="{Binding IsBusy}"
BusyContent="{Binding BusyContent}" >
<Grid>
... The page definition including sub grids, stack panels
and the combo box I'm testing along with other controls
<ops:SaveConfirmation Grid.Row="1" Margin="5"
x:Name="saveConfirmation"
SavedState="{Binding VendorSaved, Mode=TwoWay}" />
</Grid>
</toolkit:BusyIndicator/>
</Grid>
The BusyIndicator is the one from the Silverlight Toolkit and SaveConfirmation is a control we’ve written.
If I test the IsBusy binding on the BusyIndicator that works as expected. However, if I test the SavedState binding on the SaveConfirmation that fails – I set the VendorSaved property to true in the test but when I get the control the bound value is false.
var busyIndicator = GetUIElement<BusyIndicator>("activityControl");
Assert.AreEqual(busyIndicator.IsBusy, _viewModel.IsBusy, "Failed to data-bind busy indicator.");
var saveConfirmation = GetUIElement<SaveConfirmation>("saveConfirmation");
Assert.AreEqual(saveConfirmation.SavedState, _viewModel.VendorSaved, "Failed to data-bind saved state");
So the first test passes, but the second fails.
What do I need to do to ensure that the bindings of elements all the way down the tree are set up?
You’ve included the XAML for your ComboBox, but not the rest of your page. In your test you have
GetUIElement<Grid>("LayoutRoot").DataContext = _viewModel;. In the example you’re following, he defines:and then the controls on which he’s testing the bindings are nested directly inside that grid. Is your page setup the same way?