C# MVVM:View上的listview控件由模型属性更新,但不由其在ViewModel中的包装器属性更新
我正在尝试创建一个示例纯MVVM应用程序。 我的问题是,如果我将模型属性绑定到UI上的ListView项,它工作得很好,但当我尝试绑定模型属性的包装器[在ViewModel中创建]时,它不工作 在我的示例应用程序中,如果我在FamilyView.xaml\ListView控件中使用名称和位置[Properties exposed In Model]属性,它将显示项目,但如果我使用MemberName和MemberLocation[Properties exposed In ViewModel],它将不更新列表 我对MVVM中层之间关系的理解是ViewModel将视图和模型分开。如果是这样,那么我们应该使用ViewModel属性绑定到视图,而不是模型属性。请建议如何通过将列表绑定到ViewModel属性来更新列表 我的代码如下: 家庭视图.xamlC# 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],
<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}" ... />