将数据绑定到WPF中的组合框有什么要求?我无法让它发挥作用

时间:2014-02-11 23:47:15

标签: wpf data-binding combobox observablecollection

我有一个DataContext对象:

//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实例被分配给我在XAML中的Window的DataContext属性,如下所示:

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

在运行时,调试器的本地窗口显示我的窗口的DataContext属性包含ProjectManager类的实例,因此我知道DataContext正确设置并且应该可用于儿童控制。

在Window中,我的ComboBox具有以下属性集:

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

最初,Projects observable集合为空。预期的行为是,当用户单击按钮并调用Projects.Add(新项目(&#34; ProjectName&#34;))时,组合框应检测到可观察集合已更改并应将新项目添加到自身至少。但是,组合框中根本没有任何东西出现。

1 个答案:

答案 0 :(得分: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));
    }
}

Projects / 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"); }
    }
}

按钮点击:

    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