I am experimenting with WPF and I came across a problem I can't seem to figure out although I have done some work with Silverlight previously and used DataContexts, Data Bindings and INPC successfully. This time I am stuck...
I am using this code to create an instance of the application's main window:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
var viewModel = new MainVM(); //implements INotifyPropertyChanged
viewModel.Load("Brighton+UK");
window.DataContext = viewModel;
window.weatherList.ItemsSource = viewModel.WeatherInfo; //THIS WORKS
window.Show();
}
When I run the application like this, all i开发者_运维问答s fine, the ListBox on the main window displays the items found in the WeatherInfo ObservableCollection of the MainVM like it should.
However, when I comment the line out and then go into my main window's XAML, and setup the ItemsSource property of the weatherList ListBox in XAML like so:
<ListBox x:Name="weatherList"
Grid.Row="0"
ItemContainerStyle="{StaticResource stretched}"
ItemsSource="{Binding WeatherInfo}" />
The list does not get populated as I would expect, although I do set the DataContext of the MainWindow to an instance of the MainVM (as shown in the C# code excerpt).
Could someone please explain to me, WHY?
==EDIT==
All of my Main Window's XAML:
<Window x:Class="DataTemplates.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Google World Weather"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen"
xmlns:local="clr-namespace:DataTemplates" >
<!--Resources section-->
<Window.Resources>
<!--Styles-->
<Style TargetType="Label">
<Setter Property="FontSize" Value="24" />
<Setter Property="Margin" Value="10,0,0,0" />
</Style>
<Style x:Key="stretched" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Window.Resources>
<!--Command binding definition-->
<Window.CommandBindings>
<CommandBinding Command="Refresh" x:Name="cmdLoadWeatherForecast" CanExecute="cmdLoadWeatherForecast_CanExecute" Executed="cmdLoadWeatherForecast_Executed" />
</Window.CommandBindings>
<!--UI design - layout of individual controls-->
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox x:Name="weatherList" Grid.Row="0" ItemContainerStyle="{StaticResource stretched}" ItemsSource="{Binding WeatherInfo}" />
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="10" >
<TextBox Text="Brighton UK" Name="txtLocation" Width="200" FontSize="20" Margin="10" FocusManager.FocusedElement="{Binding txtLocation}" />
<Button IsDefault="True" Name="btnLoadForecast" Content="Load Weather Forecast" Command="Refresh" Margin="0,10,10,10" Padding="10"/>
</StackPanel>
</Grid>
</Window>
Thank you all for your valuable suggestion. I wasn't aware of the Binding Errors being displayed in the Output window and from there I was only one Google away from the solution.
The problem I had was that the WeatherInfo items source I was trying to bind to was a public field, not a property. Therefore, I could simply assign the WeatherInfo public ObservableCollection to the listbox's itemssource but I could not rely on the data binding mechanism to locate the WeatherInfo property in the DataContext, as WeatherInfo was not technically a property. Adding {get; private set;} to the WeatherInfo declaration in my MainVM made the data binding work as expected and I don't have to assign WeatherInfo object as ItemsSource of the listbox in code any more.
Your code should work unless ListBox is in another DataContext.
try
<ListBox x:Name="weatherList"
Grid.Row="0"
ItemContainerStyle="{StaticResource stretched}"
ItemsSource="{Binding DataContext.WeatherInfo, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type yournamespace:MainWindow}}}" />
to find out.
[Edit: Feel Stupid]
Okay, sorry, I see that you're in the StartUp...answered to quickly before...MainWindow IS the object that the ListBox is in, correct?
I would check, however, to make sure that nothing closer to the ListBox (direct parent, etc.) has a DataContext of its own.
When you load the form check the output window to see if there are any binding error messages.
A nice quick way to ensure you're DataContext is correct is to throw a button right next to the ListBox, link an event to it in the Window's codebehind and put a breakpoint. Then when you reach said breakpoint go to your immediate window and peek into your DataContext by casting it to the ViewModel:
(MainVM)DataContext
Is WeatherInfo static or not?
Can you post your MainVM object code?
精彩评论