gpt4 book ai didi

c# - 在新线程上使用 ObservableCollection

转载 作者:行者123 更新时间:2023-11-30 17:57:27 24 4
gpt4 key购买 nike

几天前我创建了this thread因为我无法从另一个线程更新 ObservableCollection。这是线程的解决方案:

Dispatcher.CurrentDispatcher.BeginInvoke(new Action(delegate
{
TheTVDB theTvdb = new TheTVDB();
foreach (TVSeries tvSeries in theTvdb.SearchSeries("Dexter"))
{
this.Overview.Add(tvSeries);
}
}),
DispatcherPriority.Background);

但是,这似乎并不是真正的解决方案,因为在执行委托(delegate)时 UI 仍然卡住。我的猜测是,上面的代码并没有真正在另一个线程上运行任何东西,而是将它全部分派(dispatch)给 UI 线程。所以我真正想做的是自己创建一个新线程并进行加载(这发生在 theTvdb.SearchSeries() 中)。然后我将迭代结果并将它们添加到我的 ObservableCollection 中,这必须发生在 UI 线程上。

这种方法听起来对吗?

我想出了下面的方法,我认为它会加载结果并将它们添加到 ObervableCollection 并在我的 ListView 中显示它们,而不会卡住 UI。

Thread thread = new Thread(new ThreadStart(delegate
{
TheTVDB theTvdb = new TheTVDB();
List<TVSeries> dexter = theTvdb.SearchSeries("Dexter");

foreach (TVSeries tvSeries in dexter)
{
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(delegate
{
this.Overview.Add(tvSeries);
}),
DispatcherPriority.Normal);
}
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

以上不会产生任何错误。相反什么也没有发生。 UI 不会卡住,但不会更新。 Overview 中的对象没有出现在 UI 中,我已经测试过绑定(bind)是正确的。如果我不加载它们并将它们添加到另一个线程上的 ObservableCollection,这些对象将正确显示。

我尝试过的另一种解决方案是使用 MTObservableCollection from this answer到一个类似的问题。当使用 ObservableCollection 的那个子类时,我自己没有发送任何东西。这给了我以下错误:

Must create DependencySource on same Thread as the DependencyObject.

谁能告诉我怎么做:

  1. 在单独的线程上加载一些内容
  2. 使用第 1 步的结果更新绑定(bind)到 ListView 的 ObservableCollection
  3. 在不卡住 UI 的情况下在 UI 中显示结果

我希望你能进一步帮助我。

更新:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:acb="clr-namespace:AttachedCommandBehavior"
mc:Ignorable="d"
x:Class="TVSeriesLibrary.OverviewView"
x:Name="UserControl"
d:DesignWidth="512"
d:DesignHeight="480">

<UserControl.Resources>
<DataTemplate x:Key="CoverTemplate">
<StackPanel Orientation="Horizontal">
<Image Width="82" Height="85" Stretch="Fill" Source="{Binding Cover}" Margin="10,10,0,10"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="#515050">
<Grid.Resources>
<ResourceDictionary>
<Style x:Key="ItemContStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="#282828" />
<Setter Property="Margin" Value="0,0,0,5" />
<Setter Property="Padding" Value="0" />
</Style>
</ResourceDictionary>
</Grid.Resources>

<ListView Height="112"
Width="488"
Margin="12,150,12,218"
Foreground="#ffffff"
Background="#515050"
VerticalContentAlignment="Center"
BorderThickness="0"
ItemTemplate="{StaticResource CoverTemplate}"
ItemsSource="{Binding Overview}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>

<ListView Height="170"
Margin="10,298,10,0"
VerticalAlignment="Center"
Foreground="#ffffff"
Background="#515050"
VerticalContentAlignment="Center"
BorderThickness="0"
Width="488" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Path=Overview}"
SelectedItem="{Binding Path=SelectedTVSeries}"
ItemContainerStyle="{StaticResource ItemContStyle}">
<ListView.Resources>
<ResourceDictionary>
<Style x:Key="hiddenStyle" TargetType="GridViewColumnHeader">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</ResourceDictionary>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Cover" Width="auto" HeaderContainerStyle="{StaticResource hiddenStyle}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Path=Cover}" Height="50" Margin="-6,0,0,0" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>


<GridViewColumn Header="Title" Width="200" HeaderContainerStyle="{StaticResource hiddenStyle}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

<GridViewColumn Header="Year" Width="100" HeaderContainerStyle="{StaticResource hiddenStyle}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=DisplayYear}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

<GridViewColumn Header="Button" Width="135" HeaderContainerStyle="{StaticResource hiddenStyle}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Details" Width="100" Height="20" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

</GridView>
</ListView.View>
</ListView>
</Grid>

</UserControl>

最佳答案

在您希望保持响应的应用程序中的任何“繁重”工作中采用多线程方法是正确的思考方式,因此您走在正确的轨道上。

但是,当您在这里创建和使用其他线程时,您仍然过分依赖 Dispatcher。考虑一下,这里使用多线程,您的过程应该如下所示:

  1. 在单独的线程上完成繁重的工作。
  2. 完成后,要求调度员根据需要更新 UI。

这会减少 Dispatcher 的负载。

您是否考虑过使用任务?从“干净代码”的角度来看,它们很棒,但在这里也适用,因为使用 Task Continuation,您可以将任务链接在一起以在 UI 上一旦繁重的工作完成后调用相关代码线程。

看看 answer here一个好的开始。

如果您之后需要,我很乐意提供更详细的示例。

编辑:正如另一个答案中提到的,BackgroundWorker 在这里同样有效......从线程的角度来看,最终结果完全相同。我就是喜欢 Task 语法!

编辑:只是想我会提供一些代码。为了简单起见,我现在将避免继续。考虑以下可以完成繁重工作的方法:

    public void HeavyLifting(Action<List<Items>> callback)
{
Task<List<Items>> task = Task.Factory.StartNew(
() =>
{
var myResults = new List<Items>();

// do the heavy stuff.

return myResults;
});

callback.Invoke(task.Result);
}

然后对于您的 UI(例如在您的 ViewModel 中),您可以同时调用和处理回调。需要时,调用“繁重的工作”并传入您的回调:

HeavyLifting(this.HandleHeavyLiftingCompleted);

然后,您传递的方法是在任务完成时执行回调。请注意,这里是我要求 Dispatcher 完成工作的地方:

private void HandleHeavyLiftingCompleted(List<Items> results)
{
this._uiDispatcher.BeginInvoke(
new Action(() => { this.MyItems = new ObservableCollection<Items>(results); }));
}

请注意,在这种情况下,涉及的 UI 工作是更新我从 View 绑定(bind)到的 ObvservableCollection。对于此处的示例,我使用了一个随机的“Item”对象,它可以是您喜欢的任何对象!

我正在使用 Cinch,因此依靠服务来获取相关的 Dispatcher(您在这里看到的是 this._uiDispatcher)。在您的情况下,您可以使用此处其他问题中提到的方法获得对它的引用。

此外,如果您有时间阅读,这里有一些很棒的信息 here关于 WPF 线程模型。

关于c# - 在新线程上使用 ObservableCollection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13230017/

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