我在使用MVVM架构时遇到了一个主要问题,我还没有看到它直接解决甚至提到过。在多线程应用程序中,视图可以在完全构造视图模型之前启动数据绑定,从而创建绑定失败。
以下是一个例子:
public class StocksViewModel
{
// blah blah
public IOrderedEnumerable<KeyValuePair<string, string>> AvailableStocks
{
get
{
// This could take a minute or two
return StockService.GetAvailableStocks(User);
}
}
public double Quantity
{
get => Quantity;
set
{
Quantity = value; RaisePropertyChanged(nameof(Quantity));
}
}
public double Symbol
{
get => Symbol;
set
{
Symbol = value; RaisePropertyChanged(nameof(Symbol));
}
}
}
这里是XAML:
<ComboBox x:Name="Quantity" Grid.ColumnSpan="2" Grid.Column="2" SelectedValue="{x:Bind Mode=TwoWay, Path=ViewModel.Quantity}" DisplayMemberPath="Value" SelectedValuePath="Key" ItemsSource="{x:Bind ViewModel.AvailableStocks}" />
<ComboBox x:Name="Symbol" Grid.ColumnSpan="2" Grid.Column="2" SelectedValue="{x:Bind Mode=TwoWay, Path=ViewModel.Symbol}" DisplayMemberPath="Value" SelectedValuePath="Key" ItemsSource="{x:Bind ViewModel.AvailableStocks}" />
如您所见,数据绑定可能无法预测。如果StockService需要几秒钟,则数量和符号永远不会有机会数据绑定到AvailableStock。
处理这种情况的处方方法是什么?
答案 0 :(得分:1)
我的方法是采取与你在这里不同的道路。在我的视图模型的构造函数中,我将创建一个readonly ObservableCollection<KeyValuePair<string, string>>
。那时我也会开始一个新的线程来呼叫GetAvailableStocks
。结果返回后,您可以填充ObservableCollection
。但是,在检索数据时,我会包含加载图标或类似的想法,以便用户知道我们仍在收集结果。
视图模型应该加载它可以的所有数据,并准备好在收到数据时显示其他数据。如果数据可以预先加载并传递到视图模型中,那就更好了,但这种情况总是不会发生。
代码示例(请原谅我在移动设备上的格式化):
public class ViewModel
{
readonly ObservableCollection<KeyValuePair<string, string>> _availableStocks;
public ObservableCollection<KeyValuePair<string, string>> AvailableStocks
{
get => _availableStocks;
}
public bool IsExecuting { get; set; }
public ViewModel()
{
_availableStocks = new ObservableCollection<KeyValuePair<string, string>>();
IsExecuting = true;
TaskFactory.StartNew(() =>
{
var results = StockService.GetAvailableStocks(User);
foreach (var stock in results)
AvailableStocks.Add(stock);
IsExecuting = false;
}
}
}
此代码未经测试,但我希望它可以帮助您解决问题!