gpt4 book ai didi

wpf - 使用 Dispatcher 在 WPF 列表框中异步加载项目列表

转载 作者:行者123 更新时间:2023-12-03 10:13:47 27 4
gpt4 key购买 nike

我正在创建一个 WPF 解决方案,它使用 MVVM 模式异步加载搜索控件中的搜索项。作为 WPF 用户控件的搜索控件是用一个文本框创建的,用于输入搜索文本和搜索按钮以及一个隐藏的列表框,当它在其中加载搜索的项目列表时将可见。该用户控件依次嵌入到另一个 WPF View 中,该 View 具有某些项目的 TreeView 。此 View 有一个 View 模型,其中加载 TreeView 的搜索项的逻辑将加载到搜索控件中。一直以来,这一直在同步发生,无需使用任何 Dispatcher 调用。但是,在更改请求之后,我想使用 Dispatcher 在不同的线程中异步发生这种情况。

谁能告诉我如何处理 View 模型类中搜索控件的调度程序,以便使用 MVVM 模式调用 BeginInvoke,其中我的 View 模型不知道 View ?任何线索将不胜感激。

public ObservableCollection<Details> CatalogSearchResults { get; private set; }

private void ExecuteSearchCommand(object parameter)
{
CatalogSearchResults.Clear();
if (string.IsNullOrEmpty(parameter.ToString())) return;

searchtext = (string)parameter;
searchtext.Trim();

SetSearchResults();
}

private void SetSearchResults()
{
BackgroundWorker bw = new BackgroundWorker();

bw.DoWork += LoadResults;
bw.RunWorkerCompleted += this.LoadResultsCompleted;

bw.RunWorkerAsync();
}

private void LoadResults(object sender, DoWorkEventArgs args)
{
IsSearchInProgress = true;
foreach (var category in _rootCategory.Recurse(FindChildren))
{
if (category.CommentDetails != null)
{
//limitation - there is no direct way to add range to observable collection.
//Using linq query would result in two loops rather than one.
foreach (var node in category.Details)
{
if (node.Name.IndexOf(searchtext, StringComparison.CurrentCultureIgnoreCase) >= 0
|| node.PrecannedText.IndexOf(searchtext, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate { CatalogSearchResults.Add(node); });
Thread.Sleep(100);
}
}
}
}
IsSearchInProgress = false;
}

在 xaml 中,我将 Search 控件的 Items 属性绑定(bind)到 CatalogSearchResults:
 <ctrl:SearchControl x:Name="Ctrl" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Top"   ToolTip="Search" Command="{Binding SearchCommand}"   Grid.ColumnSpan="3"                                                                             
CommandParameter="{Binding Text, RelativeSource={RelativeSource Self}}"
Items ="{Binding CatalogSearchResults}" > </ctrl:SearchControl>

谢谢,
索米亚

最佳答案

这是一个简单的实现,展示了如何使用 BackgroundWorkerDoWork 时更新 UI 线程上的对象正在运行 - 在本例中,有一个 ListBox在绑定(bind)到 FilteredItems 的 UI 中, 和 ItemsSourceUserControl 的属性类型 IEnumerable :

    FilteredItems = new ObservableCollection<object>();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerAsync();

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = (BackgroundWorker) sender;
var result = ItemsSource
.OfType<object>()
.Where(x => x.ToString().Contains(_FilterText));
foreach (object o in result)
{
// Pass each object found to bw_ProgressChanged in the UserState argument.
// This updates the UI as each item is found.
bw.ReportProgress(0, o);
}
}

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// FilteredItems is bound to the UI, but it's OK to update it here because
// the ProgressChanged event handler runs on the UI thread.
FilteredItems.Add(e.UserState);
}

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
}

请注意,调用 ReportProgress每次你找到一个项目都是非常低效的,因为你正在用 Invoke 编码跨线程找到的每个项目。称呼。根据过滤实际花费的时间,最好累积一堆结果并通过 List<object>bw_ReportProgress而不仅仅是一个 object .

关于wpf - 使用 Dispatcher 在 WPF 列表框中异步加载项目列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3886236/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com