c# - 如何在 ListBox 在其 ItemsSource 集合更改后更新时显示等待光标?
问题描述
我有ListBox
一个视图模型属性 ( Photos
),它是一个ObservableCollection
包含图像文件路径的对象。显示ListBox
图像,可能有很多:
看法:
<ListBox ItemsSource="{Binding Path=Photos}"
SelectionChanged="PhotoBox_SelectionChanged">
...
</ListBox>
后面的代码(可以改进为异步运行......):
void RefreshPhotoCollection (string path) {
Photos.Clear ();
var info = new DirectoryInfo (path);
try {
foreach (var fileInfo in info.EnumerateFiles ()) {
if (FileFilters.Contains (fileInfo.Extension)) {
Photos.Add (new Photo (fileInfo.FullName));
}
}
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) {
...
}
}
RefreshPhotoCollection
通过使用这种涉及 IDisposable 的方法,我设法在运行时显示等待光标:
using (this.BusyStackLifeTracker.GetNewLifeTracker())
{
// long job
}
但是当视图被通知集合更改时,光标会在此方法结束时重置为指针。然后ListBox
呈现自己,但完成时不显示等待光标。我有问题。
如何ListBox
在更新完成之前显示等待光标?
解决方案
这个模式做了这些事情:
- 将光标更改逻辑放在标志变量中以供其他用途。
- 为其他线程提供一种安全的方式来更改gui 线程上的 GUI 项。
- 在允许 UI 响应的单独线程中添加照片。
- 为了安全起见,添加到集合中的实际照片是在 Gui 线程上完成的。
- 添加照片时,等待光标不会 跳转/更改状态。
- 检查最短等待处理时间,以呈现做某事的样子。可以根据需要更改等待时间。如果没有达到最小等待时间,则不做额外的时间。
虚拟机上的通知这允许任何非 gui 线程执行安全的 gui 操作。
public static void SafeOperationToGuiThread(Action operation)
{
System.Windows.Application.Current?.Dispatcher?.Invoke(operation);
}
状态标志 然后提供一个持续标志,如果需要,可以重新使用视图,这也设置光标:
private bool _IsOperationOnGoing;
public bool IsOperationOnGoing
{
get { return _IsOperationOnGoing; }
set {
if (_IsOperationOnGoing != value)
{
_IsOperationOnGoing = value;
SafeOperationToGuiThread(() => Mouse.OverrideCursor = (_IsOperationOnGoing) ? Cursors.Wait : null );
OnPropertyChanged(nameof(IsOperationOnGoing));
}
}
}
在单独的线程中添加照片然后在您的照片添加中,执行此模式,其中 gui 线程关闭光标,然后单独的任务/线程加载照片。还监控时间以显示可行的一致等待时间光标:
private Task RunningTask { get; set; }
void RefreshPhotoCollection (string path)
{
IsOperationOnGoing = true;
RunningTask = Task.Run(() =>
{
try {
TimeIt( () =>
{
... // Enumerate photos like before, but add the safe invoke:
SafeOperationToGuiThread(() => Photos.Add (new Photo (fileInfo.FullName););
},
4 // Must run for 4 seconds to show the user.
);
}
catch() {}
finally
{
SafeOperationToGuiThread(() => IsOperationOnGoing = false);
}
});
}
}
等待时间检查
如何在视图 ListBox 更新完成之前保持等待光标,以便用户真正知道 UI 何时再次响应?
这是等待操作的方法,如果没有达到最小操作时间,将填写等待时间:
public static void TimeIt(Action work, int secondsToDisplay = 2)
{
var sw = Stopwatch.StartNew();
work.Invoke();
sw.Stop();
if (sw.Elapsed.Seconds < secondsToDisplay)
Thread.Sleep((secondsToDisplay - sw.Elapsed.Seconds) * 1000);
}
如果需要,可以将其修改为使用异步调用,只需进行最少的更改。
替代配置文件中的@mins 标记行:
Light a man a fire and he is warm for a day.
Set a man a fire and he is warm for the rest of his life.
推荐阅读
- visual-studio - 如何让 Visual Basic 释放 PictureBox 图像?
- firebase - 如何将列表值传递给新的小部件
- javascript - 当窗口最小化时,Electron+React useState 不会更新
- python - 树莓派零 2 W 上的硒
- blazor - Visual Sstudio 2022 Current 中的热重载不适用于现有的 Blazor 应用程序
- unix - 64 位机器上 64 位可执行文件的 Exec Format 错误
- python - 将 TSV 文件中的列加载到 python 列表中
- python - 龟屏监听允许多线程?
- python - Pyspark:从随机项目函数创建一个集合
- javascript - 如何使用 javaScript 为所有 td 添加相同的类