views:

96

answers:

3

I have a simple class that provides state codes like this:

public class StateProvider
{
    static string[] _codes = new string[]
    {
        "AL",
        "AK",
        ...
    };

    public string[] GetAll()
    {
        return _codes;
    }
}

My model class that supports the view looks a little like this:

public class ProjectModel : ChangeNotifier
{
    StateProvider _states = new StateProvider();

    public ProjectModel()
    {
        Project = LoadProject();
    }

    ProjectEntity _project;
    public ProjectEntity Project
    {
        get { return _project; }

        set
        {
            _project = value;
            FirePropertyChanged("Project");
        }
    }

    public string[] States { get { return _states.GetAll(); } }
}

And my ComboBox XAML looks like this:

<ComboBox SelectedValue="{Binding Project.State, Mode=TwoWay}" SelectedValuePath="{Binding RelativeSource={RelativeSource Self}}" ItemsSource="{Binding States}" />

The binding works from the UI to the entity - if I select the state from the combo then the value gets pushed to the project entity and I can save it. However, if I shutdown and reload, the state code value doesn't bind from the entity to the UI and the combo shows nothing selected. Then, of course, a subsequent save nulls the entity's state value.

I want this very simple since I want to display state codes and save state codes (I don't want to display the full state name). So I don't want to have to muck with creating a State class that has Code and FullName properties and avoid having to use the SelectedValuePath and DisplayMemberPath properties of the combobox.

Edit: Added to the code how ProjectModel does change notification. Note that the ProjectEntity class does this too. Trust me, it works. I've left it out because it also inherits from an Entity base class that does change notification through reflection. TwoWay binding works on everything but for the combobox.

+1  A: 

You have to at least implement IPropertyNotifyChanged on your ProjectModel class

public class ProjectModel : INotifyPropertyChanged
{
        public event PropertyChangedEventHandler PropertyChanged;

and implement the Project property as below for binding to work other than 1-way-1-time.

public ProjectEntity Project
{
    get { return (ProjectEntity)GetValue(ProjectProperty); }
    set { SetValue(ProjectProperty, value); }
}

// Using a DependencyProperty as the backing store for Project.  
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty ProjectProperty =
    DependencyProperty.Register("Project",
                                typeof(ProjectEntity),
                                typeof(ProjectModel),
                                new PropertyMetadata(null,
                                    new PropertyChangedCallback(OnProjectChanged)));

static void OnProjectChanged(object sender, DependencyPropertyChangedEventArgs args)
{
    // If you need to handle changes
}
Enough already
First, I'm pretty sure this doesn't depend on property change notification because the Project class is hydrated before the view even begins loading. And second, both the view model and the Project class already implement INotifyPropertyChanged (the code above is abbreviated). Besides, ALL the other properties on my Project class are TwoWay binding just fine. It's just this silly state combo.
xanadont
Sorry, we can only work with what we are shown. If you abbreviate the code you need to give people a heads-up to avoid wasting time. Thanks.
Enough already
I amended the question. Check the "Edit:" note.
xanadont
A: 

Change your ProjectModel class to this:

public class ProjectModel : ChangeNotifier
{
    StateProvider _states = new StateProvider();

    public ProjectModel()
    {
        Project = LoadProject();

        States = new ObservableCollection<string>(_states.GetAll());
    }

    ProjectEntity _project;
    public ProjectEntity Project
    {
        get { return _project; }

        set
        {
            _project = value;
            FirePropertyChanged("Project");
        }
    }

    public ObservableCollection<string> States { get; set; }
}

Also make sure that ProjectEntity also implements INotifyPropertyChanged.

Yogesh
A: 

Wow, whodathought it'd came down to this:

<ComboBox ItemsSource="{Binding States}" SelectedValue="{Binding Project.State, Mode=TwoWay}" />

It turned out it was the order in which I placed the attributes in the XAML. The SelectedValue binding was happening before the ItemsSource binding and thus there were no items in the combobox when the SelectedValue was bound.

Wow, this just seems like a really bad thing.

xanadont