【问题标题】:Binding to model property not working绑定到模型属性不起作用
【发布时间】:2015-01-04 12:04:55
【问题描述】:

我需要将域模型的属性值(加载到视图模型中)绑定到我的外壳视图上的控件内容,但是它根本不起作用(内容保持空白)。我怎样才能解决这个问题?域模型是否也需要实现 INotifyPropertyChanged?

ShellViewModel

public class ShellViewModel : Conductor<ProjectViewModel>.Collection.OneActive, IShell
{

    public ShellViewModel() {
        ActivateItem(new ProjectViewModel(new Project { ProjectName = "Test" }));
    }

}

ShellView(标签控件)

<TabControl x:Name="Items">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ActiveItem.Project.ProjectName}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
</TabControl>

项目视图模型

public class ProjectViewModel : Screen
{

    private Project _project;

    public Project Project
    {
        get { return _project; }
        private set
        {
            _project = value;
            NotifyOfPropertyChange(() => _project);
        }
    }

    public ProjectViewModel(Project project)
    {
        Project = project;
    }    

项目

public class Project
{

    public string ProjectName { get; set; }

}

【问题讨论】:

  • 你的 ShellViewModel 中有属性“ActivateItem”吗??
  • 或者更好的是,你有一个名为 Items 的集合吗?
  • @TYY,为什么是Items?这只是 TabControl 的名称?
  • 他正在使用 caliburn,因此通常您命名控件,以便 Caliburn 查看您的视图模型并找到要绑定的适当对象。如果您注意到 OP 没有指定任何与 TabControl 的绑定(那么他是如何创建 TabItems 这就是我问这个问题的原因)。
  • 如果您在某处放置断点并使用您的代码示例检查您的TabControl.DataContext,也就是Items.DataContext,它会解析哪种类型的集合?它应该是一个项目集合,其中每个项目都具有属性ActiveItem.Project.ProjectName,因此您可以调用类似Collection[x].ActiveItem.Project.ProjectName

标签: c# wpf mvvm data-binding caliburn.micro


【解决方案1】:

不要让您的 Conductor.Collection 为 ProjectViewModel 类型,使其成为 Screen 或 IScreen,因为 ProjectViewModel 继承 Screen 是最佳选择。完成后,您在 ShellViewModel 的构造函数中进行集合调用。

shellviewmodel 将如下所示。

public ShellViewModel(/*IEnumerable<Screen> screens*/){  // Not Necessary 

     //automatically finds what is in the IoC Container 
     //(MEF, SimpleContainer, AutoFac, StructureMap etc... 
     //Assuming your using one...

     //this.Items.AddRange(screens);
      this.Items.Add(new ProjectViewModel(new Project(){ ProjectName = "Test";}));   
}
protected override OnInitialize(){

}

模板

<TabControl x:Name="Items">
    <TabControl.ItemTemplate>
        <DataTemplate>
          <StackPanel>
              <TextBlock Text="{Binding DisplayName}" />
              <TextBlock Text="{Binding Project.ProjectName}" /> 
          </StackPanel>                     
        </DataTemplate>
 </TabControl.ItemTemplate>

我这样做的原因DisplayName 它已经在 Screen 的类对象中作为属性...这样您就不必做太多额外的工作,编写您的 ViewModel。

public class ProjectViewModel : Screen{
  private Project _project;
  public ProjectViewModel(Project project){

    DisplayName = "Test" ;

    Project = project;
  }  
  public Project Project{
       get{ return _project;}
       private set{
           _project = value;
           NotifyOfPropertyChange();
       }
    }
 }

在您要显示的模型对象上将继承 PropertyChangedBase

在 ViewModel 上,它们将继承 PropertyChangedBased、Screen 甚至是 Conductor(例如)。所有人都有不同的需求,以适应您想要做的事情。

要查看的另一件事是项目中的 IoC 容器实际上有 2 个。 1 SimpleContainer 2 MEF,大多数(如果不是全部)样本都使用 MEF。

【讨论】:

  • 我的导体集合是特定类型 ProjectViewModel 因为首先,这是我需要显示的唯一类型的视图模型,其次,我获得了对 ShellViewModel 绑定的智能支持,因为这样, ShellViewModel 称为 ProjectViewModel。另外,我不确定您要告诉我什么,因为除了您对 ProjectViewModel 指挥的评论之外,我的代码完全相同。我唯一的问题是 {Binding Project.ProjectName} 没有绑定任何东西(ProjectName 不会显示在 TabItem 标题中,即使它已设置)..
  • 这是一个示例应用程序,我认为您已经设置了比较 2 并告诉我您与我的不同之处? skydrive.live.com/redir?resid=C9472B51C27DC8FE!84921
  • 您有 ProjectView.xaml 用户控件吗?上面的示例使用 CM 2.0
【解决方案2】:

如果你想使用绑定,那么你绑定的属性对象必须实现 INotifyPropertyChanged。否则你只会看到初始值。所以是的,简单的方法是您的域模型实现 INotifyPropertyChanged。

   <TextBlock Text="{Binding ActiveItem.Project.ProjectName}" />

使用这一行 wpf 不关心 OnPropertyChanged("Project") 因为它绑定到 ProjectName。

【讨论】:

    最近更新 更多