Listview UWP、MVVM和级联列表视图
我对UWP和两个ListView越来越着迷了。这个场景很简单:我在第二页中有一个listview(listview和listViewField) 我有一个ViewModel,如:Listview UWP、MVVM和级联列表视图,listview,mvvm,uwp,observablecollection,Listview,Mvvm,Uwp,Observablecollection,我对UWP和两个ListView越来越着迷了。这个场景很简单:我在第二页中有一个listview(listview和listViewField) 我有一个ViewModel,如: public class FormViewModel : BaseViewModel { public ObservableCollection<TableInfo> Tables; } 第二次更新 正如@MZetko所建议的,我添加了绑定x:Bind vm.Tables,Mode=OneWay,
public class FormViewModel : BaseViewModel {
public ObservableCollection<TableInfo> Tables;
}
第二次更新
正如@MZetko所建议的,我添加了绑定x:Bind vm.Tables,Mode=OneWay
,当我添加新项目时,列表视图会更新
最后一个问题是如何将所选项目与表单连接(第3点)
然后,我应该在表单中包含来自模型listview的数据
<StackPanel x:Name="stackTable" Orientation="Vertical" Padding="10">
<TextBlock>Table name</TextBlock>
<TextBox x:Name="textboxTableName"
Text="{Binding ElementName=listView, Path=SelectedItem.Name}" />
<TextBlock>Project namespace</TextBlock>
<TextBox x:Name="textboxNameSpace"
Text="{Binding ElementName=listView, Path=SelectedItem.ProjectNameSpace}" />
</StackPanel>
表名
项目名称空间
这段代码显示表单中的项,一个用于表,另一个用于字段。现在我的问题是:如果我想添加一条新记录或删除一条记录,我该怎么做
我四处看看,发现了那些链接
提前感谢您的帮助 第二个ListView绑定到TableInfo的Fields属性,该属性的类型为
List
。列表不支持数据绑定更新UI所依赖的更改通知
将列表
更改为可观察收集
,您将看到更好的结果
顺便提一下,我建议只绑定第二个ListView中的ItemsSource,而不是绑定DataContext和ItemsSource(这需要两次刷新UI)。它应该简单到:
<ListView x:Name="listView" ItemsSource="{x:Bind vm.Tables}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="mdl:TableInfo">
<TextBlock Text="{x:Bind Name}" FontSize="25" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView x:Name="listViewTable"
ItemsSource="{Binding ElementName=listView, Path=SelectedItem.Fields}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="mdl:FieldInfo">
<TextBlock Text="{x:Bind Name}" FontSize="25" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
希望有帮助。您的第二个ListView正在绑定到TableInfo的Fields属性,该属性的类型为
List
。列表不支持数据绑定更新UI所依赖的更改通知
将列表
更改为可观察收集
,您将看到更好的结果
顺便提一下,我建议只绑定第二个ListView中的ItemsSource,而不是绑定DataContext和ItemsSource(这需要两次刷新UI)。它应该简单到:
<ListView x:Name="listView" ItemsSource="{x:Bind vm.Tables}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="mdl:TableInfo">
<TextBlock Text="{x:Bind Name}" FontSize="25" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView x:Name="listViewTable"
ItemsSource="{Binding ElementName=listView, Path=SelectedItem.Fields}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="mdl:FieldInfo">
<TextBlock Text="{x:Bind Name}" FontSize="25" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
希望有帮助。如果我理解正确,问题是第二个列表视图在添加新字段时不会更新 问题在于,字段列表的类型为
list
。UWP中的数据绑定基于INotifyPropertyChanged
和INotifyCollectionChanged
接口<代码>列表也不实现,因此无法自动通知用户界面它已更改。为此,您需要将其替换为observetecollection
。将项目添加到此集合时,UI将自动更新为新项目
然而,不幸的是,这仍然不足以更新字段。observedcollection
类可以观察到项目的更改,如Add
或Remove
,但不能观察其中单个项目的更改。
要做到这一点,您必须确保FieldInfo
类实现了INotifyPropertyChanged
,并且每当要观察属性更改时,都会调用PropertyChanged
事件
接口的最常见实现如下所示:
public event propertychangedventhandler PropertyChanged;
私有void NotifyPropertyChanged([CallerMemberName]字符串propertyName=”“)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
现在,在所有需要调用NotifyPropertyChanged
方法的属性中:
私有字符串_description=”“;
公共字符串描述
{
得到
{
返回描述;
}
设置
{
_描述=值;
NotifyPropertyChanged();
}
}
由于
[CallerMemberAttribute]
的原因,您不必指定propertyName
参数,它将由编译器自动填写。如果我理解正确,问题是第二个列表视图在添加新字段时不会更新
问题在于,字段列表的类型为list
。UWP中的数据绑定基于INotifyPropertyChanged
和INotifyCollectionChanged
接口<代码>列表也不实现,因此无法自动通知用户界面它已更改。为此,您需要将其替换为observetecollection
。将项目添加到此集合时,UI将自动更新为新项目
然而,不幸的是,这仍然不足以更新字段。observedcollection
类可以观察到项目的更改,如Add
或Remove
,但不能观察其中单个项目的更改。
要做到这一点,您必须确保FieldInfo
类实现了INotifyPropertyChanged
,并且每当要观察属性更改时,都会调用PropertyChanged
事件
接口的最常见实现如下所示:
public event propertychangedventhandler PropertyChanged;
私有void NotifyPropertyChanged([CallerMemberName]字符串propertyName=”“)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
现在,在所有需要调用NotifyPropertyChanged
方法的属性中:
私有字符串_description=”“;
公共字符串描述
{
得到
{
返回描述;
}
设置
{
_描述=值;
NotifyPropertyChanged();
}
}
因为[CallerMemberAttribute]
public int SelectedTableInfoIndex
{
get { return _selectedTableInfoIndex; }
set {
_selectedTableInfoIndex = value;
if (_selectedTableInfoIndex >= 0) {
_selectedTableInfo = Tables[_selectedTableInfoIndex];
}
}
}
private int _selectedTableInfoIndex = -1;
public TableInfo SelectedTableInfo
{
get {
return (_selectedTableInfoIndex >= 0) ? Tables[_selectedTableInfoIndex] : null;
}
set {
_selectedTableInfo = value;
RaisePropertyChanged("SelectedTableInfo");
}
}
private TableInfo _selectedTableInfo;
<StackPanel x:Name="stackTable" Orientation="Vertical" Padding="10">
<TextBlock>Table name</TextBlock>
<TextBox x:Name="textboxTableName"
Text="{Binding ElementName=listView, Path=SelectedItem.Name}" />
<TextBlock>Project namespace</TextBlock>
<TextBox x:Name="textboxNameSpace"
Text="{Binding ElementName=listView, Path=SelectedItem.ProjectNameSpace}" />
</StackPanel>
<ListView x:Name="listView" ItemsSource="{x:Bind vm.Tables}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="mdl:TableInfo">
<TextBlock Text="{x:Bind Name}" FontSize="25" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView x:Name="listViewTable"
ItemsSource="{Binding ElementName=listView, Path=SelectedItem.Fields}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="mdl:FieldInfo">
<TextBlock Text="{x:Bind Name}" FontSize="25" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class BaseViewModel : INotifyPropertyChanged {
#region Property changed
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notifies the property changed.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void NotifyPropertyChanged(string propertyName, Action<bool> message) {
if (this.PropertyChanged != null) {
// property changed
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
message?.Invoke(this.IsValid);
}
}
/// <summary>
/// Raises the property changed.
/// </summary>
/// <param name="property">The property.</param>
protected void RaisePropertyChanged(string property) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
// SetField(()=> somewhere.Name = value; somewhere.Name, value)
// Advanced case where you rely on another property
protected bool SetProperty<T>(T currentValue, T newValue, Action DoSet,
[CallerMemberName] String property = null) {
if (EqualityComparer<T>.Default.Equals(currentValue, newValue)) return false;
DoSet.Invoke();
RaisePropertyChanged(property);
return true;
}
#endregion
}