CollectionView ItemsSource 绑定视觉更新 (Xamarin.Forms)
CollectionView ItemsSource binding visual update (Xamarin.Forms)
我试图在我的应用程序中加入一些 MVVM 模式,但我 运行 遇到了数据可视化表示的问题。如果绑定的 observablecollecrion 更新了数据,但视觉对象没有更新。
一些代码:
视图模型:
public class HlavnaViewModel : BaseViewModel
{
public HlavnaViewModel()
{
}
private Doklady _selectedDok;
public Doklady vm_selectedDok
{
get => _selectedDok;
set
{
_selectedDok = value;
OnPropertyChanged(nameof(vm_selectedDok));
update_polozky();
}
}
public async void update_polozky()
{
Polozky dok = new Polozky() { id_doklad = _selectedDok.id };
ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(await App.Database.GetPolozkyAsync(dok));
vm_polozky = pol;
}
private ObservableCollection<Polozky> _polozky;
public ObservableCollection<Polozky> vm_polozky
{
get => _polozky;
set
{
_polozky =value;
OnPropertyChanged(nameof(vm_polozky));
}
}
}
在XAML:
<CollectionView x:Name="polozky" SelectionMode="Single" ItemsSource="{Binding vm_polozky}">...
基础视图模型:
public class BaseViewModel : INotifyPropertyChanged
{
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
终于在视图中:
public Hlavna()
{
InitializeComponent();
hvm = new HlavnaViewModel();
this.BindingContext = hvm;
}
如果我 select CollectionView 中的一行设置了 vm_selectedDok 绑定,它 select 是该项目,触发 update_polozky(),vm_polozky 填充了正确的数据,但视觉效果只是不显示来自 vm_polozky 的项目。
我读过几个类似的问题,但我不知道我在哪里犯了错误。
编辑:
所以问题出在其他地方,我的 grid.rowdefinitions 设置错了,因此网格在可见区域之外。
@ToolmakerSteve 在调用 async/await 时提出了很好的建议,请阅读他的回答。
基本上归结为,不要这样做:ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(await App.Database.GetPolozkyAsync(dok));
每当您创建一个新的 ObservableCollection
时,它都会丢失与 UI 的数据绑定。使用 .Clear()
清除 ObservableCollection
并使用 for
循环向其中添加新项目。例如:
public async void update_polozky()
{
Polozky dok = new Polozky() { id_doklad = _selectedDok.id };
var results = await App.Database.GetPolozkyAsync(dok);
vm_polozky.Clear();
foreach(var item in results)
vm_polozky.Add(item);
}
有两种替代方法可以解决此问题。
一种方式是杰拉尔德的回答。这对于小的 collections 没问题,但是如果要添加很多项目,可能 会更慢。
第二种方法是做你已经做的 - 替换 collection。但是您的代码中需要修复。
您调用 update_polozky
的方式无法可靠地工作。您不会在 await
.
中启动 async/await
序列
替换:
update_polozky();
有:
Device.BeginInvokeOnMainThread(async () => {
await update_polozky();
});
可选:也可以进行此更改。 (虽然它不应该是必要的。)这提供了一个放置断点的好地方,以查看“结果”是否获得预期的内容。
替换:
ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(await App.Database.GetPolozkyAsync(dok));
有:
var result = await App.Database.GetPolozkyAsync(dok);
ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(result);
其他程序员的重要注意事项:
第二种方法(“替换 collection”)依赖于 ObservableCollection
的 setter
中的 OnPropertyChanged(nameof(vm_polozky));
。
你有那个,所以对你来说不是问题。我向任何可能改编此代码的人提及这一点。
例如,我看到有人试图直接设置私有值,例如:
// Don't do this to replace the collection. XAML won't know you changed it!
_myPrivateField = new ObservableCollection<MyItem>(result);
我也看到有人试图拥有一个没有 setter:
的 ObservableCollection
// This is okay UNLESS you replace the collection - in which case you need `OnPropertyChanged(nameof(MyCollection))` somewhere:
public ObservableCollection<MyItem> MyCollection { get; set; }
我试图在我的应用程序中加入一些 MVVM 模式,但我 运行 遇到了数据可视化表示的问题。如果绑定的 observablecollecrion 更新了数据,但视觉对象没有更新。 一些代码: 视图模型:
public class HlavnaViewModel : BaseViewModel
{
public HlavnaViewModel()
{
}
private Doklady _selectedDok;
public Doklady vm_selectedDok
{
get => _selectedDok;
set
{
_selectedDok = value;
OnPropertyChanged(nameof(vm_selectedDok));
update_polozky();
}
}
public async void update_polozky()
{
Polozky dok = new Polozky() { id_doklad = _selectedDok.id };
ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(await App.Database.GetPolozkyAsync(dok));
vm_polozky = pol;
}
private ObservableCollection<Polozky> _polozky;
public ObservableCollection<Polozky> vm_polozky
{
get => _polozky;
set
{
_polozky =value;
OnPropertyChanged(nameof(vm_polozky));
}
}
}
在XAML:
<CollectionView x:Name="polozky" SelectionMode="Single" ItemsSource="{Binding vm_polozky}">...
基础视图模型:
public class BaseViewModel : INotifyPropertyChanged
{
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
终于在视图中:
public Hlavna()
{
InitializeComponent();
hvm = new HlavnaViewModel();
this.BindingContext = hvm;
}
如果我 select CollectionView 中的一行设置了 vm_selectedDok 绑定,它 select 是该项目,触发 update_polozky(),vm_polozky 填充了正确的数据,但视觉效果只是不显示来自 vm_polozky 的项目。
我读过几个类似的问题,但我不知道我在哪里犯了错误。
编辑: 所以问题出在其他地方,我的 grid.rowdefinitions 设置错了,因此网格在可见区域之外。
@ToolmakerSteve 在调用 async/await 时提出了很好的建议,请阅读他的回答。
基本上归结为,不要这样做:ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(await App.Database.GetPolozkyAsync(dok));
每当您创建一个新的 ObservableCollection
时,它都会丢失与 UI 的数据绑定。使用 .Clear()
清除 ObservableCollection
并使用 for
循环向其中添加新项目。例如:
public async void update_polozky()
{
Polozky dok = new Polozky() { id_doklad = _selectedDok.id };
var results = await App.Database.GetPolozkyAsync(dok);
vm_polozky.Clear();
foreach(var item in results)
vm_polozky.Add(item);
}
有两种替代方法可以解决此问题。
一种方式是杰拉尔德的回答。这对于小的 collections 没问题,但是如果要添加很多项目,可能 会更慢。
第二种方法是做你已经做的 - 替换 collection。但是您的代码中需要修复。
您调用 update_polozky
的方式无法可靠地工作。您不会在 await
.
async/await
序列
替换:
update_polozky();
有:
Device.BeginInvokeOnMainThread(async () => {
await update_polozky();
});
可选:也可以进行此更改。 (虽然它不应该是必要的。)这提供了一个放置断点的好地方,以查看“结果”是否获得预期的内容。
替换:
ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(await App.Database.GetPolozkyAsync(dok));
有:
var result = await App.Database.GetPolozkyAsync(dok);
ObservableCollection<Polozky> pol = new ObservableCollection<Polozky>(result);
其他程序员的重要注意事项:
第二种方法(“替换 collection”)依赖于 ObservableCollection
的 setter
中的 OnPropertyChanged(nameof(vm_polozky));
。
你有那个,所以对你来说不是问题。我向任何可能改编此代码的人提及这一点。
例如,我看到有人试图直接设置私有值,例如:
// Don't do this to replace the collection. XAML won't know you changed it!
_myPrivateField = new ObservableCollection<MyItem>(result);
我也看到有人试图拥有一个没有 setter:
的 ObservableCollection// This is okay UNLESS you replace the collection - in which case you need `OnPropertyChanged(nameof(MyCollection))` somewhere:
public ObservableCollection<MyItem> MyCollection { get; set; }