开发者

Two-way bind a combobox to a simple string array

开发者 https://www.devze.com 2023-01-16 16:38 出处:网络
I have a simple class that provides state codes like this: public class StateProvider { static string[] _codes = new string[]

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.


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
}


Wow, whodathought it'd come 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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消