多线程 WPF 应用程序:调度程序调用。更有效的方法?

发布于 2024-10-27 14:32:55 字数 694 浏览 1 评论 0原文

我正在使用 .NET 3.5 。

我正在为一个项目制作 WPF 应用程序,我只是想了解一些有关调度程序和多线程的见解。我的程序的一个示例:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () =>_aCollection.Add(new Model(aList[i], aSize[i]))));

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () => _Data.Add(new DataPoint<double, double>(Id, aList[i]))));

 Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () => _historical[0].Add(aList[i])));

我知道 WPF 不喜欢另一个线程访问创建它的对象以外的对象。但是,我认为肯定有一种比调用这么多调度程序更好的方法,有人可以至少将我推向正确的方向(如果有更好的解决方案的话)。

I am using .NET 3.5 .

I am making a WPF application for a project and I was just looking a bit of insight regarding the Dispatcher and multithreading. An example of my program:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () =>_aCollection.Add(new Model(aList[i], aSize[i]))));

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () => _Data.Add(new DataPoint<double, double>(Id, aList[i]))));

 Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () => _historical[0].Add(aList[i])));

I understand that WPF does not like when another thread accessing an object other than the one that created it. However, I was thinking there has to surely be a better way than making so many dispatcher invokes, could someone please push me in the right direction at least (if there is a better solution that is).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

太阳公公是暖光 2024-11-03 14:32:56

您的问题源于事实,即 ObservableCollection 不会自动将更改分派给 UI 线程。这与简单的 INotifyPropertyChanged 不同,它是自动执行的。我建议创建您自己的特定 ObservableCollection,它实现 INotifyCollectionChanged,自动将更改分派到 UI 线程。

您可以在此处查看示例: SynchronizedObservableCollection 和 BindableCollection

旧答案/问题:
您是否使用 DependencyObjectDependencyProperties为了你的绑定?如果是,那就放弃吧。人们对此进行了多次讨论,这是使用 INotifyPropertyChanged 代替。只需要使用调度程序来修改 GUI 对象本身的属性,从您的示例中可以明显看出,这不是您在做什么。绑定本身是通过调度程序自动运行的。

另请参阅视图模型:POCO 与 DependencyObjects

Your problem stems from fact, that ObservableCollection doesn't automaticaly dispatch changes to UI thread. This is different form simple INotifyPropertyChanged, that does it automaticaly. I would recomend creating your own specific ObservableCollection, that implements INotifyCollectionChanged, that automaticaly dispatches changes to UI thread.

You can see example here: SynchronizedObservableCollection and BindableCollection

Old answer/question:
Are you using DependencyObject and DependencyProperties for your binding? If yes, then drop it. It was discussed many times and this is one of the bigger reasons why to use INotifyPropertyChanged instead. Only need to use dispatcher is to modify properties of GUI objects themselves and its obvious from your example, that is not what are you doing. And binding itself is run through dispatcher automaticaly.

Also see View Models: POCOs versus DependencyObjects

梦在深巷 2024-11-03 14:32:55

您可以从在调用中不那么冗长开始,即

Application.Current.Dispatcher.Invoke(() =>_aCollection.Add(new Model(aList[i], aSize[i])));

我喜欢使用的另一个技巧是创建一个像这样的快捷方法:

public static void UiInvoke(Action a)
{
  Application.Current.Dispatcher.Invoke(a);
}

然后您要做的事情甚至更少,如下所示:

UiInvoke(() =>_aCollection.Add(new Model(aList[i], aSize[i])));

使用dispatcher.Invoke()实际上就是您的方式将操作返回到 UI 线程,这可能是首先创建这些对象 (_aCollection) 的地方。如果相关项目没有与 UI 线程直接交互,那么您可以在不同的线程上创建/操作它们,从而无需使用调度程序。当然,根据您所做的事情,这种方法可能会变得更加复杂。

You can start by being less verbose in your calls, i.e.

Application.Current.Dispatcher.Invoke(() =>_aCollection.Add(new Model(aList[i], aSize[i])));

Another trick that I like to use is to make a shortcut method like this:

public static void UiInvoke(Action a)
{
  Application.Current.Dispatcher.Invoke(a);
}

Then you have even less to do, as in:

UiInvoke(() =>_aCollection.Add(new Model(aList[i], aSize[i])));

Using dispatcher.Invoke() is really just how you get the action back onto the UI thread, which is probably where these objects (_aCollection) were created in the first place. If the items in question don't have direct interaction with the UI thread, then you can create / manipulate them on a different thread, removing the need to use the dispatcher. Of course this approach could become more complicated depending on what you are doing.

猫弦 2024-11-03 14:32:55

最简单的方法是将所有三个调用合并为一个:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () =>
                      {
                          _aCollection.Add(new Model(aList[i], aSize[i]);
                          _Data.Add(new DataPoint<double, double>(Id, aList[i]);
                          _historical[0].Add(aList[i])
                      }));

The easiest way would be to combine all three calls into one:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () =>
                      {
                          _aCollection.Add(new Model(aList[i], aSize[i]);
                          _Data.Add(new DataPoint<double, double>(Id, aList[i]);
                          _historical[0].Add(aList[i])
                      }));
怀念你的温柔 2024-11-03 14:32:55

如果您使用的是.Net 4.0,我会考虑使用 System.Threading.Tasks。这似乎是延续的一个主要示例。

IF you're using .Net 4.0 I would look into using System.Threading.Tasks. This seems like a prime example for continuations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文