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?