2014-02-11 2 views
1

У меня есть DataContext объект:Каковы требования для привязки данных к combobox в WPF? Я не могу заставить его работать

//Simple DataContext object with an observable collection and a property representing the currently selected project which uses the INotifyPropertyChanged interface 
public class ProjectManager: ObservableObject 
{ 
    public ObservableCollection<Project> Projects {get;set;} 

    public ProjectManager() 
    { 
     //Assignment occurs in constructor and never changes, so I don't think "Projects" property needs to implement INotifyPropertyChanged. It has a value by the time anything else could possibly reference it and it's always the same collection which will have items added and removed from it 
     Projects = new ObservableCollection<Project>(); 
    } 
    private Project loadedProject = null; 
    public Project CurrentProject 
    { 
     get {return loadedProject;} 
     set 
     { 
      LoadProject(value); //load the project before updating internal variable 
      SetProperty(ref loadedProject, value); //SetProperty uses C# 5.0 [CallerMemberName] attribute on optional parameter to obtain "CurrentProject" property name since it's the caller; this is a popular implementation of ObservableObject 
     } 
    } 
} 

У меня есть класс, представляющий элемент в наблюдаемой коллекции:

public class Project: ObservableObject 
{ 
    private string _name; 
    public string Name 
    { 
     get {return _name;} 
     set {SetProperty(ref _name, value);} //ObservableObject implements INotifyProperyChanged 
    } 
} 

ObservableObject реализуется здесь:

public class ObservableObject: INotifyPropertyChanged 
{ 
    //C# 5.0 feature: "CallerMemberName" must be affixed to *optional* parameter and is automatically filled in with the member name of the method that calls SetProperty when the parameter is omitted 
    protected bool SetProperty<T>(ref T prop, T value, [CallerMemberName] string propertyName = null) 
    { 
     if (EqualityComparer<T>.Default.Equals(prop,value)) return false; 
     prop = value; 
     OnPropertyChanged(propertyName); 
     return true; 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 
} 

Экземпляр ProjectManager присваивается свойству DataContext моего окна в XAML следующим образом:

<Window.DataContext> 
    <p:ProjectManager /> 
</Window.DataContext> 

Во время работы локальное окно отладчика показывает, что свойство DataContext моего окна содержит экземпляр класса ProjectManager, поэтому я знаю, что DataContext задан правильно и должен быть доступен для дочерних элементов управления.

В окне, мой ComboBox имеет следующие атрибуты набор:

ItemsSource="{Binding Projects, Mode=OneWay}" DisplayMemberPath="Name" SelectedValuePath="Name" SelectedValue="{Binding CurrentProject, UpdateSourceTrigger=PropertyChanged}"

Первоначально проекты наблюдаемой коллекция пуста. Ожидаемое поведение заключается в том, что, когда пользователь нажимает кнопку, и я вызываю Projects.Add (новый проект («имя_проекта»)), combobox должен обнаруживать, что наблюдаемая коллекция изменилась и должна добавить новый элемент к себе, по крайней мере. Однако ничего не появляется в выпадающем списке.

+0

как вы добавляете товар из кода зачем использовать Binding 'Mode = OneWay'? –

+0

Одностороннее связывание происходит от источника к целевому элементу пользовательского интерфейса. Комбобокс никогда не будет обновлять коллекцию, поэтому combobox должен обновляться при изменении коллекции. Это один из способов привязки. – Triynko

ответ

1

Можем ли мы увидеть ваш код ObservableObject? Я не вижу ничего плохого в вашей привязке. Если я реализую то, что вы описали следующим образом, все работает по назначению, что заставляет меня думать, что это ваша реализация INotifyPropertyChanged.

public class ObservableObject : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void RaisePropertyChangedEvent(string propertyName) 
    { 
     var Handler = PropertyChanged; 
     if (Handler != null) 
      Handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

Проекты/DataContext:

public class ProjectManager : ObservableObject 
{ 
    public ObservableCollection<Project> Projects { get; set; } 

    public ProjectManager() 
    { 
     Projects = new ObservableCollection<Project>(); 

    } 
    private Project loadedProject = null; 
    public Project CurrentProject 
    { 
     get { return loadedProject; } 
     set 
     { 
      //LoadProject(value); //load the project before updating internal variable 
      //SetProperty(ref loadedProject, value); //SetProperty uses C# 5.0 [CallerMemberName] attribute on optional parameter to obtain "CurrentProject" property name since it's the caller; this is a popular implementation of ObservableObject 
      loadedProject = value; 
      RaisePropertyChangedEvent("CurrentProject"); 
     } 
    } 
} 

public class Project : ObservableObject 
{ 
    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     //set { SetProperty(ref _name, value); } //ObservableObject implements INotifyProperyChanged 
     set { _name = value; RaisePropertyChangedEvent("Name"); } 
    } 
} 

Кнопка Click:

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     ProjectManager PM = DataContext as ProjectManager; 

     PM.Projects.Add(new Project() { Name = "New Project"}); 
    } 

XAML:

<Window.DataContext> 
    <pr:ProjectManager/> 
</Window.DataContext> 
<Grid>  
     <StackPanel Orientation="Horizontal" Height="32"> 
      <Button Height="32" Click="Button_Click">Bind</Button> 
      <ComboBox Height="32" Width="400" ItemsSource="{Binding Projects}" DisplayMemberPath="Name" 
        SelectedValuePath="Name" SelectedValue="{Binding CurrentProject}"></ComboBox> 
     </StackPanel> 
</Grid> 

Результат после Bind нажимается:

enter image description here

+0

Несомненно, я обновлю вопрос, чтобы включить код ObservableObject. – Triynko

+0

Проблема не в коде ObservableObject, проблема в том, что класс framework ObservableCollection не обновляет ComboBox, к которому он привязан. – Triynko

+0

Итак, в чем разница между моим примером (где ObservableCollection привязывается в порядке) и вашим фактическим кодом? Используя вашу реализацию ObservableObject, мое тестовое приложение также работает нормально. – Gareth

Смежные вопросы