我正在尝试发现避免UI锁定的最好方法,当您一次对UI进行大量更新时。
基本前提是,在启动时,我的工具在后台工作进程中运行一个perforce FSTAT。这将生成一个非常大的文件及其信息列表。完成此操作后,在其RunWorkerCompleted函数中,我将此信息传播到TreeView中的UI。
然而,这涉及到大量的属性更新!这取决于它传播到的文件的数量。它可以是5000+文件。这将完全锁定UI大约3-5秒。
我想知道我是否可以异步更新UI,这样我说,一次传播10-20个文件,仍然让UI线程继续更新,以便它仍然有响应。
谢谢。
发布于 2015-03-16 23:21:50
如果使用属性绑定更新TreeView内部的信息,则可以将Binding.IsAsync标志设置为true。如果您不使用绑定来更新值,那么这可能是需要考虑的问题。
另一种选择是更新所有属性,但不调用属性的PropertyChanged事件(假设您正在使用INotifyPropertyChanged更新绑定),直到所有数据都已更改,然后为任务上的每个属性调用PropertyChanged事件,因此,它仍然是异步的,但即使使用5000+绑定更新,也不应花费3-5秒。
发布于 2015-03-17 00:18:06
你提出的许多建议最终让我得到了一个好的答案。下面是我的代码。基本上,我们可以使用ReportProgress来允许UI在运行时更新。然后根据我们希望这种情况发生的频率进行调整。下面是我的解决方案。
关键是每N个项目调用一次PropegateMetaData (我指定了25个)。然后该列表被清空。
这将调用每25个项目的报告进度,然后继续。并最终将其余部分传递给WorkerCompleted。
public static void Refresh(List<string> refreshPaths)
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
List<string> filesPath = null;
if (refreshPaths == null)
{
filesPath = DatabaseViewModel.Instance.Records.Select(record => record.Filepath).ToList();
}
else
{
filesPath = new List<string>(refreshPaths);
}
if (m_Repository != null && filesPath.Count > 0)
{
IList<FileSpec> lfs = new List<FileSpec>();
int index = 0;
foreach (DataRecord rec in DatabaseViewModel.Instance.Records)
{
lfs.Add(new FileSpec(new LocalPath(rec.Filepath), null));
index++;
if (index > MaxFilesIteration)
{
GetFileMetaDataCmdOptions opts = new GetFileMetaDataCmdOptions(GetFileMetadataCmdFlags.AllRevisions, null, null, 0, null, null, null);
worker.ReportProgress(0, m_Repository.GetFileMetaData(lfs, null));
lfs.Clear();
index = 0;
}
}
args.Result = m_Repository.GetFileMetaData(lfs, null); //pass the remaining results across
}
};
worker.ProgressChanged += (sender, args) => PropegateMetaData(args.UserState as IList<FileMetaData>);
worker.RunWorkerCompleted += (sender, args) => PropegateMetaData(args.Result as IList<FileMetaData>);
worker.RunWorkerAsync();
}
private static void PropegateMetaData(IList<FileMetaData> fileList)
{
IList<FileMetaData> fileState = fileList as IList<FileMetaData>;
if (fileState != null)
{
foreach (FileMetaData fmd in fileState)
{
DataRecord currentRecord = DatabaseViewModel.Instance.GetRecordByFilepath(fmd.LocalPath.Path);
if (currentRecord != null)
{
switch (fmd.Action)
{
case FileAction.Add:
currentRecord.P4Status = P4FileState.Added;
break;
case FileAction.Edit:
currentRecord.P4Status = P4FileState.Edit;
break;
case FileAction.MoveAdd:
currentRecord.P4Status = P4FileState.MoveAdd;
break;
default:
currentRecord.P4Status = P4FileState.None;
break;
}
}
}
}
}https://stackoverflow.com/questions/29080167
复制相似问题