简体   繁体   English

WPF C#长时间运行

[英]WPF C# Long running operation

Basically i am having problems with c# threads within wpf and how to use them properly. 基本上我在wpf中的c#线程以及如何正确使用它们方面遇到问题。

At first i bumped into my app hanging due to a long running operation. 起初,由于长时间运行,我碰到了挂起的应用程序。 After researching how to resolve this, i decided to use the Dispatcher BeginInvoke method and put the running operation on its own thread. 在研究了解决方法之后,我决定使用Dispatcher BeginInvoke方法并将运行操作放在自己的线程上。 However the amount of code that has to be sent to the UI thread is too much to make any difference. 但是,必须发送到UI线程的代码量太大,无法发挥任何作用。

Here is a simplified version of what i am doing that causes the hanging: 这是导致挂起的操作的简化版本:

for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 100; j++)
    {
        for (int k = 0; k < 100; k++)
        {
            Image image = new Image();

            // ... Do stuff with image here 

            Binding binding = new Binding();

            // ... Bind some properties to the image

            // Add the image to a list and a canvas
            List.Add(image);
            SomeCanvas.Children.Add(image);
        }
    }
}

As you see most of the processing in the operation consists of using controls. 如您所见,该操作中的大多数处理都包含使用控件。 Therefore they have to be dispatched to the UI thread asynchronously. 因此,它们必须异步地分派到UI线程。 After doing this, basically all of the operation is on the UI thread and again the application hangs :/ 完成此操作后,基本上所有操作都在UI线程上,并且应用程序再次挂起:/

Any suggestions on what i can do in this situation? 在这种情况下,我有什么建议吗? Many Thanks 非常感谢

Creating so many visual objects in a tight loop is bound to be sluggish. 在一个紧密的循环中创建如此多的视觉对象注定是缓慢的。 Perhaps you could try splitting this into two phases. 也许您可以尝试将其分为两个阶段。 Inside your tight loop you merely create a placeholder for the image. 在紧密循环内,您只需要为图像创建一个占位符。 Say a rectangle with a filled colour to indicate where the image will be shown in the future. 请说出一个填满颜色的矩形,以表示将来将在哪里显示该图像。

Then in another set of threads you actually load the contents of the images and setup the bindings. 然后,在另一组线程中,实际上是加载图像的内容并设置绑定。 That way the user interface stays response at all times. 这样,用户界面始终保持响应。 The user sees placeholders immediately and then sees the actual images replace the placeholders as they are loaded in real time. 用户立即看到占位符,然后看到实际图像替换了实时加载的占位符。 You see this all the time on web pages where the placeholders get filled with the actual content when it is downloaded. 您会一直在网页上看到这些内容,在这些网页上,占位符会在下载时被实际内容填充。

You're certainly not leveraging all of the cores of a modern processor by running everything on the UI thread. 您肯定不会通过在UI线程上运行所有内容来利用现代处理器的所有核心。

It looks like you're processing multiple images from your UI thread. 看来您正在处理UI线程中的多个图像。 I suspect that the image processing is the CPU intensive task, not the other items hinted at in your code sample. 我怀疑图像处理是CPU密集型任务,而不是代码示例中暗示的其他项目。 If that's the case, consider doing the image manipulation on a number of different threads and having the UI thread do what it needs to do when each worker thread completes. 如果是这种情况,请考虑在多个不同的线程上进行图像处理,并让UI线程完成每个工作线程完成后需要做的事情。

If you can use .NET 4, the Task Parallel Library makes it very easy to work with threads. 如果可以使用.NET 4,则任务并行库使使用线程非常容易。 I find the BlockingCollection very useful for coordinating work between the UI thread and worker threads. 我发现BlockingCollection对于协调UI线程和辅助线程之间的工作非常有用。 There are good code examples in the link I provided. 我提供的链接中有很好的代码示例。

Here's the sample, creating a large number of UI objects asynchronously: 这是示例,以异步方式创建大量UI对象:

public partial class Window1 : Window
    {
        public delegate void CreateCanvasHandler(Grid parent, int index);

        public Window1()
        {
            InitializeComponent();

            int count = 10000;

            this.TestCreateAsync(count);
        }

        private void TestCreateAsync(int count)
        {
            for (int i = 0; i < count; i++)
            {
                //check the DispatecherOperation status
                this.LayoutRoot.Dispatcher.BeginInvoke(new CreateCanvasHandler(this.CreateCanvas),
                    DispatcherPriority.Background,
                    new object[2] 
                    { 
                        this.LayoutRoot,
                        i
                    });   
            }
        }

        private void CreateCanvas(Grid parent,
            int index)
        {
            Canvas canvas = new Canvas()
            {
                Width = 200,
                Height = 100
            };

            canvas.Children.Add(new TextBlock()
            {
                Text = index.ToString(),
                FontSize = 14,
                Foreground = Brushes.Black
            });

            Thread.Sleep(100);

            parent.Children.Add(canvas);
        }
    }

You may ensure that the processing required to be done by the UI thread is handled in its idle time, ie when it is not processing events etc. 您可以确保UI线程所需的处理在其空闲时间内进行,即当它不处理事件等时。

This is done by using the priority setting System.Windows.Threading.DispatcherPriority.SystemIdle when dispatching an operation. 这是通过分派操作时使用优先级设置System.Windows.Threading.DispatcherPriority.SystemIdle来完成的。

This link aught to provide the details you need (label A Single-Threaded Application with a Long-Running Calculation) 该链接提供了您所需的详细信息 (标签为具有长期计算功能的单线程应用程序)

This will surely decrease the rate at which your processing completes, but it will allow you to maintain a fully functional UI whilst processing. 这肯定会降低处理的完成速度,但可以让您在处理过程中保持功能完整的UI。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM