在WPF中排队事件的最佳实践

时间:2014-10-02 16:44:31

标签: c# wpf multithreading mvvm

我有一个WPF(MVVM)项目,我有多个视图模型,每个视图模型都有一个按钮,可以在同一个数据源上启动不同的分析,在这种情况下是一个文件。该文件无法共享,因此如果在同一时间按下按钮,则第二次调用将失败。

我需要一种方法来对按钮进行排队,这样每个分析都可以按顺序运行,但我似乎无法让它工作。我尝试使用静态SemaphoreSemaphoreSlimMutex,但它们似乎会停止所有内容(Wait()函数似乎会阻止当前运行的分析)。我尝试了一个带有静态对象的lock()命令,但它似乎没有阻止任何一个事件(我得到文件共享错误)。我还尝试了一个线程池(最大并发线程数为1),但它会更新UI时出现线程错误(这可能通过Invoke()调用解决)。

我的问题是WPF在这种情况下可能被认为是最佳做法吗?

编辑:我创建了一个展示我遇到的问题的模型。它位于http://1drv.ms/1s4oQ1T

3 个答案:

答案 0 :(得分:1)

我会做两件事来解决这个问题:

首先,将分析操作封装在命令模式中。如果您不熟悉它,最简单的实现是具有单个函数Execute的接口。如果要执行分析操作,只需创建其中一个。您也可以使用内置的ICommand接口来提供帮助,但请注意,此接口比通用命令模式具有更多功能。

当然,创造只是战斗的一半,所以我这样做后会把它添加到BlockingCollection。这个集合是.NET对Producer-Consumer问题的解决方案。有一个后台线程使用集合foreach方法上的GetConsumingEnumerable来使用此集合(执行其中包含的命令对象),并且您的按钮将" feed"它。

foreach (var item in bc.GetConsumingEnumerable())
{
    item.Execute();
}

阻止收集的MSDN:http://msdn.microsoft.com/en-us/library/dd267312(v=vs.110).aspx

现在,所有的信号量,等待等都是为你完成的,你只需要向队列添加一个操作(如果它需要是一个队列,考虑使用ConcurrentQueue作为{的后备集合{1}})并返回UI线程。后台线程将选择任务并运行它。

当然需要BlockingCollection来自后台线程的任何UI更新,而不是解决该问题:)。

答案 1 :(得分:0)

我建议在视图模型共享的调度对象中使用一个队列,该队列等待队列添加一个项目。按下按钮时,视图模型会将工作项添加到队列中。使用者任务每次从队列中获取一个项目,分析包含在工作项中,然后检查队列中的另一个项目,等待更多工作项目添加,如果没有要处理的工作项目。

答案 2 :(得分:0)

这里需要的是一个异步队列,这样您就可以排队这些任务而不会阻塞您的线程。 SemaphoreSlim实际上有WaitAsync方法,这使得创建这样的队列变得相当简单:

public class TaskQueue
{
    private SemaphoreSlim semaphore;
    public TaskQueue()
    {
        semaphore = new SemaphoreSlim(1);
    }

    public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
    {
        await semaphore.WaitAsync();
        try
        {
            return await taskGenerator();
        }
        finally
        {
            semaphore.Release();
        }
    }
    public async Task Enqueue(Func<Task> taskGenerator)
    {
        await semaphore.WaitAsync();
        try
        {
            await taskGenerator();
        }
        finally
        {
            semaphore.Release();
        }
    }
}

这允许您将所有顺序执行的操作排队,而不是并行执行,并且不会在任何时候阻塞任何线程。这些操作也可以是任何类型的异步操作,无论是另一个线程中的CPU绑定工作,IO绑定工作等等。