Andrew B Schultz
Andrew B Schultz

Reputation: 1512

Silverlight 5 Binding - Why isn't this working?

I can bind a combobox in the codebehind like this:

    private void comboBox1_Loaded(object sender, RoutedEventArgs e)
    {
        var combo = sender as ComboBox;
        App.SchedulerVM = new ScheduleViewModel();
        combo.DataContext = App.SchedulerVM;
        combo.ItemsSource = App.SchedulerVM.Frequency;
    }

This works - my combobox has the items from the Frequency List in the SchedulerVM object.

However, I don't want to do any of this in the codebehind. But the ways I've done this in WP7 before aren't working here. If I comment out the last line in the Loaded method above and try to set the ItemsSource in XAML, it doesn't work - nothing shows up:

<ComboBox Name="comboBox1" Loaded ="comboBox1_Loaded" ItemsSource="{Binding 
Frequency}" />

This doesn't work either:

<ComboBox Name="comboBox1" Loaded ="comboBox1_Loaded" ItemsSource="{Binding 
App.SchedulerVM.Frequency}" />

Nor this:

<ComboBox Name="comboBox1" Loaded ="comboBox1_Loaded" ItemsSource="{Binding 
SchedulerVM.Frequency}" />

Ideally, the DataContext wouldn't have to be explicitly set in the codebehind for this control either, it would be inherited from the LayoutRoot, where I've set it in the codebehind. But that's step 2 of my troubleshooting here.

What am I doing wrong? '

Thanks!

Edit The ScheduleViewModel looks like this:

namespace SchedulerUI.ViewModels
{
public class ScheduleViewModel : INotifyPropertyChanged
{
    //private properties
    private Schedule _thisSchedule; 

    //public properties
    public Schedule ThisSchedule
    {
        get { return _thisSchedule; }
        set
        {
            if (value != _thisSchedule)
            {
                NotifyPropertyChanged("ThisSchedule");
            }

            _thisSchedule = value;
        }
    }

    public List<string> Frequency = new List<string>();
    public string Test;

    //constructors
    public ScheduleViewModel()
    {
        Frequency.AddRange(new string[] { "Daily", "Weekly", "Monthly" });
        Test = "This is only a test.";
    }

    //INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
}

Here's the entire XAML:

<UserControl x:Class="SchedulerUI.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">

        <ComboBox Height="23" HorizontalAlignment="Left" Margin="34,41,0,0" Name="comboBox1" Loaded ="comboBox1_Loaded" VerticalAlignment="Top" Width="120" ItemsSource="{Binding Frequency}" />
        <TextBox BorderBrush="Black"  HorizontalAlignment="Left" Margin="34,41,0,0" Width="100" Height="100" DataContext="LayoutRoot.DataContext"  Text="{Binding  Test}" /> 

</Grid>
</UserControl>

Here's the entire codebehind:

namespace SchedulerUI
{
public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        App.SchedulerVM = new ScheduleViewModel();
        comboBox1.DataContext = App.SchedulerVM;
        List<string> testlist = App.SchedulerVM.Frequency;
        string teststring = App.SchedulerVM.Test;
    }

    private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
    {
        //App.SchedulerVM = new ScheduleViewModel();
        //var root = sender as Grid;
        //if (root != null)
        //{
        //    root.DataContext = App.SchedulerVM;
        //}
    }

    private void comboBox1_Loaded(object sender, RoutedEventArgs e)
    {
        //var combo = sender as ComboBox;
        //App.SchedulerVM = new ScheduleViewModel();
        //combo.DataContext = App.SchedulerVM;
        //combo.ItemsSource = App.SchedulerVM.Frequency;
    }
}
}

Upvotes: 0

Views: 897

Answers (1)

nemesv
nemesv

Reputation: 139748

You binding is not working, because:

  • when you set ItemsSource in XAML its get executed first and it tries to bind the wrong/empty DataContext
  • then the Loaded event is raised which will set the correct DataContext but your already existing binding won't be refreshed automatically.

If you have to set the DataContext in the codebehind do it in your views constructor:

public YourView()
{
    InitializeComponent();
    combo.DataContext = App.SchedulerVM;
}

Then the following binding should work:

<ComboBox Name="comboBox1" ItemsSource="{Binding Frequency}" />

The databinding in WPF/Silverlight needs public properties. Currently Frequency is a public field on your viewmodel change it to a property and everthing should work:

private List<string> frequency = new List<string>();
public List<string> Frequency { get { return frequency; } set { frequency = value; }

And that is why it worked your initial loaded event because you didn't used databind there but you just set the combo.ItemsSource.

Upvotes: 2

Related Questions