在WPF中,使用MVVM设计,我创建了一个屏幕,用于在点击按钮时将大量日志加载到ListView
。返回时,标签将更新以显示返回的日志数。这个过程有时需要一段时间。我们的DA正在优化过程中,但同时我需要进行以下更改以向用户表明搜索正在运行:
WaitCursor
。我有一个实现ICommand
的类,我WaitCursor
正常工作。但是,在搜索运行时,我无法获得更新要显示的标签所需的行为。我目前的代码:
MyScreen.xaml
<Button
Name="DisplayButton"
Content="Display Logs"
Command="{Binding DisplayLogsCommand}"
Margin="0,64,10,0"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Width="112"/>
<Label
Content="{Binding LogsShowingText}"
Margin="0,0,127,8"
Foreground="#FF3C3B3B"
HorizontalAlignment="Right"
Width="145" Height="24"
VerticalAlignment="Bottom"
HorizontalContentAlignment="Right"
FontSize="11"/>
MyScreenVM.cs
private Command displayLogsCommand;
private string logShowingText;
public Command DisplayLogsCommand
{
get
{
if (this.displayLogsCommand == null)
{
// Attempt 3 made here.
bool useWaitCursor = true;
Func<bool> canExecute = () => this.ValidateFields();
Action execute = () =>
{
/*
* TODO: Update this.LogsShowingText to read "Searching..."
*/
// Attempt 1 and 2 made here.
LogEntry[] entries = this.ClientConnection.GetLogs();
this.LogsShowingText = string.Format("Showing {0} Logs", entries.Length);
this.FilteredEntries = new ObservableCollection<LogEntry>(entries);
};
this.displayLogsCommand = new Command(useWaitCursor, canExecute, execute);
}
return this.displayLogsCommand;
}
}
public string LogsShowingText
{
get
{
return this.logsShowingText;
}
set
{
this.logsShowingText= value;
OnPropertyChanged("LogsShowingText");
}
}
到目前为止,结果和我相关的失败尝试如下:
返回日志后,Label只会读取&#34; 搜索... &#34;。
Application.Current.Dispatcher.Invoke(new Action(() => this.LogsShowingText = "Searching..."));
返回日志后,Label只会读取&#34; 显示N个日志&#34;。
this.LogsShowingText = string.Format("Searching...");
之前和 搜索期间,标签会读取&#34; 搜索... &#34;,然后<在返回日志后,标签显示&#34; 显示N个日志&#34;。与#2相同的代码,不同的位置。
据我所知,这可能与阻止用户界面直到操作完成有关,这清楚地解释了尝试1显示标签的最后一次排队更新,并尝试2显示标签的最后一次硬编码更新。尝试3几乎可以工作,但在用户单击按钮执行搜索之前,不应更新标签。我怎么能这样做?
答案 0 :(得分:3)
由于这是一个昂贵的命令,意味着UI在处理时挂起,您应该将其转换为异步命令。
public Command DisplayLogsCommand
{
get
{
if (this.displayLogsCommand == null)
{
bool useWaitCursor = true;
Func<bool> canExecute = () => this.ValidateFields();
Action execute = async () =>
{
this.LogsShowingText = "Searching";
// Attempt 1 and 2 made here.
LogEntry[] entries = await Task<LogEntry[]>.Run(() => this.ClientConnection.GetLogs());
this.LogsShowingText = string.Format("Showing {0} Logs", entries.Length);
this.FilteredEntries = new ObservableCollection<LogEntry>(entries);
};
this.displayLogsCommand = new Command(useWaitCursor, canExecute, execute);
}
return this.displayLogsCommand;
}
}
通过使Action
委托异步,您现在可以在Action
内等待。这使您可以在Task
中将调用包装到DataLayer并等待它。现在昂贵的操作正在运行UI线程,您的标签将在之前和之后正确更新。无需使用Dispatcher对更改进行编组。
仅当用户点击按钮执行命令时,才会更新标签。