C# MVVM:View上的listview控件由模型属性更新,但不由其在ViewModel中的包装器属性更新

C# MVVM:View上的listview控件由模型属性更新,但不由其在ViewModel中的包装器属性更新,c#,wpf,mvvm,C#,Wpf,Mvvm,我正在尝试创建一个示例纯MVVM应用程序。 我的问题是,如果我将模型属性绑定到UI上的ListView项,它工作得很好,但当我尝试绑定模型属性的包装器[在ViewModel中创建]时,它不工作 在我的示例应用程序中,如果我在FamilyView.xaml\ListView控件中使用名称和位置[Properties exposed In Model]属性,它将显示项目,但如果我使用MemberName和MemberLocation[Properties exposed In ViewModel],

我正在尝试创建一个示例纯MVVM应用程序。 我的问题是,如果我将模型属性绑定到UI上的ListView项,它工作得很好,但当我尝试绑定模型属性的包装器[在ViewModel中创建]时,它不工作

在我的示例应用程序中,如果我在FamilyView.xaml\ListView控件中使用名称和位置[Properties exposed In Model]属性,它将显示项目,但如果我使用MemberName和MemberLocation[Properties exposed In ViewModel],它将不更新列表

我对MVVM中层之间关系的理解是ViewModel将视图和模型分开。如果是这样,那么我们应该使用ViewModel属性绑定到视图,而不是模型属性。请建议如何通过将列表绑定到ViewModel属性来更新列表

我的代码如下:

家庭视图.xaml

<Window x:Class="MVVM_15thSep13.View.FamilyView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MVVM_15thSep13.ViewModel"
        Title="FamilyView" Height="283" Width="367">
    <Window.DataContext>
        <local:FamilyViewModel/>
    </Window.DataContext>
    <Grid>
        <TextBox Text="{Binding Family.Name, FallbackValue=BindingFailed}" Height="23" HorizontalAlignment="Left" Margin="12,16,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
        <TextBox Text="{Binding Family.Location, FallbackValue=BindingFailed}"  Height="23" HorizontalAlignment="Left" Margin="12,57,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
        <Button Command="{Binding AddDetailsCommand}" Content="Button" Height="23" HorizontalAlignment="Left" Margin="240,31,0,0" Name="button1" VerticalAlignment="Top" Width="93" />
        <ListView ItemsSource="{Binding FamilyCollection}" SelectedItem="{Binding Family}" Height="126" HorizontalAlignment="Left" Margin="14,110,0,0" Name="listView1" VerticalAlignment="Top" Width="319" UseLayoutRounding="True">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="120"/>
                    <GridViewColumn Header="Location" DisplayMemberBinding="{Binding Location}" Width="120"/>                    
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>
FamilyViewModel.cs

 namespace MVVM_15thSep13.ViewModel
{
    public class FamilyViewModel:ObservableObject
    {
        private FamilyModel m_Family;        
        private ObservableCollection<FamilyModel> m_FamilyCollection;
        private ICommand m_AddDetailsCommand;


        public FamilyViewModel()
        {           
            m_Family = new FamilyModel();
            m_FamilyCollection = new ObservableCollection<FamilyModel>();            
        }

        public FamilyModel Family
        {
            get { return m_Family; }
            set 
            {
                if (m_Family != value)
                {
                    m_Family = value;
                    OnPropertyChanged("Family");
                }
            }
        }
        public ObservableCollection<FamilyModel> FamilyCollection
        {
            get { return m_FamilyCollection; }
            set { m_FamilyCollection = value; }
        }       

        public ICommand AddDetailsCommand
        {
            get
            {
                if (m_AddDetailsCommand == null)
                    m_AddDetailsCommand = new RelayCommand(param => AddFamilyDetails(), null);

                return m_AddDetailsCommand;
            }
        }

        public void AddFamilyDetails()
        {
            FamilyCollection.Add(Family);
            Family = new FamilyModel();
        }
    }
}

您谈到视图模型包装器属性,但没有包装任何内容。视图模型只是将模型的属性加倍。你有两个选择;直接在模型类上实现
INotifyPropertyChanged
接口,并在视图模型中使用它们的实例(就像现在一样),或者在视图模型中实际“包装”模型的属性:

private FamilyModel data;

public string Name
{
    get { return data.Name; }
    set { data.Name = value; OnPropertyChanged("Name"); }
}

public string Location
{
    get { return data.Location; }
    set { data.Location = value; OnPropertyChanged("Location"); }
}
更新>>>

对不起,我以为你可以自己解决剩下的问题。这里的
FamilyModel
实例是一个私有字段。这在UI中永远不会绑定数据。而是绑定“包装”属性:

<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Location}" />
但是,由于您已经在模型类上直接实现了
INotifyPropertyChanged
接口,因此不需要执行此操作。。。我之所以提出这个建议,是因为您在问题标题中提到了“包装器属性”

相反,您可以只使用
Family
FamilyCollection
属性,去掉
MemberName
MemberLocation
属性,除非它们用于特定的用途。使用
系列
属性,可以像这样绑定到UI:

<TextBox Text="{Binding Family.Name}" />
<TextBox Text="{Binding Family.Location}" />
<TextBox Text="{Binding Family.Name, FallbackValue=BindingFailed}" ... />
<TextBox Text="{Binding Family.Location, FallbackValue=BindingFailed}" ... />
public void AddFamilyDetails()
{
    FamilyCollection.Add(Family);
    Family = new FamilyModel();
}
就个人而言,我认为你应该去掉你的
MemberLocation
MemberName
属性。。。他们只是把事情弄糊涂了。相反,您应该像这样使用
属性:

<TextBox Text="{Binding Family.Name}" />
<TextBox Text="{Binding Family.Location}" />
<TextBox Text="{Binding Family.Name, FallbackValue=BindingFailed}" ... />
<TextBox Text="{Binding Family.Location, FallbackValue=BindingFailed}" ... />
public void AddFamilyDetails()
{
    FamilyCollection.Add(Family);
    Family = new FamilyModel();
}
这也将使您能够做到这一点:

<ListView ItemsSource="{Binding FamilyCollection}" SelectedItem="{Binding Family}" ... />


。。。如果您还没有计算出来,它将在
文本框的
列表视图中显示所选项目的
名称
位置
值。当然,这取决于您。

您在哪里设置MemberName和MemberLocation的初始值?您在哪里提出MemberName和MemberLocation?它对模型中的更改有何反应,因此视图模型知道这些属性也是无效的,需要重新评估?@downhilefor:我不认为,我可以清楚地理解你的观点。但是我已经更新了视图和视图模型,以绑定视图模型属性。我还在那里初始化了属性变量。但它仍然不起作用。你能建议一下吗?忘了我的第一句话吧。从我看到的是,你的DisplayMemberBinding是错误的,它说MemberName。但是MemberName不是FamilyModel上的属性。你知道你根本没有包装FamilyModel吗?我试过你的建议。但这里的问题是“FamilyModel”没有绑定到UI上的任何控件,因此它仍然不会更新listview。@据我所知,Sheridan根本没有包装FamilyModel。他有一个viewmodel,其中包含一个直接使用的FamilyModel集合。请再次@Dowhilef查看,他在视图模型中有
MemberName
MemberLocation
属性。。。如果不尝试包装他的模型属性,它们是为了什么?还有,看看他的头衔。。。这就是我要做的。@Sheridan:我试图将文本框文本绑定为FamilyName.Name&Family.Location,而将列表项绑定为MemberName和MemberLocation。MemberName getter/setter使用[m_Family.Name],而MemberLocation getter/setter使用[m_Family.Location]。AddFamilyDetails()函数[在我上面发布的代码中]添加族数据和Familycollection。DataContext也在视图中设置[可以在我最初发布的代码中看到]。但是,现在有了这些更改,listview也不会得到更新。@Sheridan:我只希望在ViewModel的视图上使用属性,而不是直接从模型中使用属性。我是否可以要求您复制粘贴我在VisualStudio应用程序中的原始代码,并使用MemberName和MemberLocation进行ListView绑定,而不是使用Name和Location,以便我们可以在同一页面上。我正在尝试一些事情,但它不适合我。
public void AddFamilyDetails()
{
    FamilyCollection.Add(Family);
    Family = new FamilyModel();
}
<ListView ItemsSource="{Binding FamilyCollection}" SelectedItem="{Binding Family}" ... />