Question

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 is 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>
Was it helpful?

Solution 2

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.

OTHER TIPS

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.

  1. When you load the form check the output window to see if there are any binding error messages.

  2. 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

  3. Is WeatherInfo static or not?

  4. Can you post your MainVM object code?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top