كيفية القيام بما يلي: جدولة العمل في سياق معين المزامنة

يوضح هذا المثال كيفية إلى استخدام TaskScheduler.FromCurrentSynchronizationContextالأسلوب في تطبيقات "البنية الأساسية لبرامج" العروض التقديمية Windows (WPF) إلى جدولة مهمة تشغيل نفس مؤشر ترابط الذي تم تاريخ الإنشاء عنصر تحكم واجهة (واجه المستخدم) مستخدم في.

الإجراءات

لإنشاء مشروع WPF

  1. في ‏‫Visual Studio، إنشاء WPF تطبيق المشروع وتسميته.

  2. في عرض "تصميم"، قم بسحب عنصر تحكم نسخة من إلى olbox إلى سطح التصميم. في عرض XAML، قم بتعيين المحاذاة الأفقية كـ "يسار". يهم الحجم لأن عنصر التحكم سيتم تغيير حيوي حجم عند تشغيل الوقت. أقبل الاسم الافتراضي، "image1".

  3. اسحب زر من من مربع الأدوات إلى الجزء الأيمن السفلي من نافذة تطبيق. انقر نقراً مزدوجاً فوق زر لإضافة معالج حدث Click. في عرض الشجري XAML، عين Contentخاصية زر إنشاء فسيفساء"وتعيين المحاذاة الأفقية به ك"يسار".

  4. في MainWindow.xaml.cs ملف، استخدم تعليمات برمجية التالية إلى استبدال المحتويات الكاملة ملف. تأكد من أن يطابق اسم مساحة الاسم اسم مشروع.

  5. إضغط على F5 لتشغيل التطبيق. كلما قمت بالنقر فوق الزر، يجب أن يتم عرض ترتيب جديد من الإطارات المتجانبة.

المثال

الوصف

يلي مثال ينشئ فسيفسائي للصور التي تم تحديدها بشكل عشوائي من الدليل معين. يتم استخدام الكائنات WPF إلى تحميل وتغيير حجم الصور. بعد ذلك، يتم تمرير بكسل raw إلى مهمة الذي يستخدم ParallelFor()تكرار حلقي لكتابة بيانات بكسل في كبير أحادية البايت الصفيف. لا التزامن هو المطلوب لأنه لا توجد إطارات متجانبة الثاني تشغل نفس العناصر من الصفيف. الإطارات المتجانبة كما يمكن كتابة في أي ترتيب لأن موضعها هو حسابها بشكل مستقل عن أي قطعة أخرى. صفيفة قطر أيمن متوسط هو ثم تمرير لإحدى مهام التي يتم تنفيذها على مؤشر الترابط واجهة المستخدم، حيث بيانات بكسل هو تم تحميلهه في عنصر تحكم نسخة.

الرمز

using System;
using System.Collections.Generic;

using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace wpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int fileCount;
        int colCount;
        int rowCount;
        private int tilePixelHeight;
        private int tilePixelWidth;
        private int largeImagePixelHeight;
        private int largeImagePixelWidth;
        private int largeImageStride;
        PixelFormat format;
        BitmapPalette palette;

        public MainWindow()
        {
            InitializeComponent();

            // For this example, values are hard-coded to a mosaic of 8x8 tiles.
            // Each tile is 50 pixels high and 66 pixels wide and 32 bits per pixel.
            colCount = 12;
            rowCount = 8;
            tilePixelHeight = 50;
            tilePixelWidth = 66;
            largeImagePixelHeight = tilePixelHeight * rowCount;
            largeImagePixelWidth = tilePixelWidth * colCount;
            largeImageStride = largeImagePixelWidth * (32 / 8);
            this.Width = largeImagePixelWidth + 40;
            image1.Width = largeImagePixelWidth;
            image1.Height = largeImagePixelHeight;


        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {

            // For best results use 1024 x 768 jpg files at 32bpp.
            string[] files = System.IO.Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures\", "*.jpg");

            fileCount = files.Length;
            Task<byte[]>[] images = new Task<byte[]>[fileCount];
            for (int i = 0; i < fileCount; i++)
            {
                int x = i;
                images[x] = Task.Factory.StartNew(() => LoadImage(files[x]));
            }

            // When they�ve all been loaded, tile them into a single byte array.
            var tiledImage = Task.Factory.ContinueWhenAll(
                images, (i) => TileImages(i));

            // We are currently on the UI thread. Save the sync context and pass it to
            // the next task so that it can access the UI control "image1".
            var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();

            //  On the UI thread, put the bytes into a bitmap and
            // and display it in the Image control.
            var t3 = tiledImage.ContinueWith((antedecent) =>
            {
                // Get System DPI.
                Matrix m = PresentationSource.FromVisual(Application.Current.MainWindow)
                                            .CompositionTarget.TransformToDevice;
                double dpiX = m.M11;
                double dpiY = m.M22;

                BitmapSource bms = BitmapSource.Create( largeImagePixelWidth,
                    largeImagePixelHeight,
                    dpiX,
                    dpiY,
                    format,
                    palette, //use default palette
                    antedecent.Result,
                    largeImageStride);
                image1.Source = bms;
            }, UISyncContext);
        }

        byte[] LoadImage(string filename)
        {
            // Use the WPF BitmapImage class to load and 
            // resize the bitmap. NOTE: Only 32bpp formats are supported correctly.
            // Support for additional color formats is left as an exercise
            // for the reader. For more information, see documentation for ColorConvertedBitmap.

            BitmapImage myBitmapImage = new BitmapImage();
            myBitmapImage.BeginInit();
            myBitmapImage.UriSource = new Uri(filename);
            tilePixelHeight = myBitmapImage.DecodePixelHeight = tilePixelHeight;
            tilePixelWidth = myBitmapImage.DecodePixelWidth = tilePixelWidth;
            myBitmapImage.EndInit();

            format = myBitmapImage.Format;
            int size = (int)(myBitmapImage.Height * myBitmapImage.Width);
            int stride = (int)myBitmapImage.Width * 4;
            byte[] dest = new byte[stride * tilePixelHeight];

            myBitmapImage.CopyPixels(dest, stride, 0);

            return dest;
        }

        int Stride(int pixelWidth, int bitsPerPixel)
        {
            return (((pixelWidth * bitsPerPixel + 31) / 32) * 4);
        }

        // Map the individual image tiles to the large image
        // in parallel. Any kind of raw image manipulation can be
        // done here because we are not attempting to access any 
        // WPF controls from multiple threads.
        byte[] TileImages(Task<byte[]>[] sourceImages)
        {
            byte[] largeImage = new byte[largeImagePixelHeight * largeImageStride];
            int tileImageStride = tilePixelWidth * 4; // hard coded to 32bpp

            Random rand = new Random();
            Parallel.For(0, rowCount * colCount, (i) =>
            {
                // Pick one of the images at random for this tile.
                int cur = rand.Next(0, sourceImages.Length);
                byte[] pixels = sourceImages[cur].Result;

                // Get the starting index for this tile.
                int row = i / colCount;
                int col = (int)(i % colCount);
                int idx = ((row * (largeImageStride * tilePixelHeight)) + (col * tileImageStride));

                // Write the pixels for the current tile. The pixels are not contiguous
                // in the array, therefore we have to advance the index by the image stride
                // (minus the stride of the tile) for each scanline of the tile.
                int tileImageIndex = 0;
                for (int j = 0; j < tilePixelHeight; j++)
                {
                    // Write the next scanline for this tile.
                    for (int k = 0; k < tileImageStride; k++)
                    {
                        largeImage[idx++] = pixels[tileImageIndex++];
                    }
                    // Advance to the beginning of the next scanline.
                    idx += largeImageStride - tileImageStride;
                }
            });
            return largeImage;
        }
    }
}

التعليقات

يوضح هذا المثال كيفية تحريك بيانات إيقاف مؤشر ترابط واجهة المستخدم، وتعديله باستخدام متوازى loops والمهام الالكائنات، ومن ثم مرر إلى مهمة التي يتم تنفيذها تشغيل مؤشر ترابط واجهة المستخدم. Th هو المنهج هو مفيداً عندما يكون لديك باستخدام "مكتبة متوازٍ للمهام" لتنفيذ العمليات التي لا يدعمها WPF API، أو غير كاف سريعة. هناك طريقة أخرى لإنشاء فسيفسائي نسخة في WPF هو لاستخدام WrapPanelالكائن وقم بإضافة الصور إلى it. WrapPanelسوف مؤشر العمل لتعيين موضع الإطارات المتجانبة. ومع ذلك، يمكن هذا العمل تشغيل LY أداؤه تشغيل مؤشر ترابط لواجهة المستخدم.

وهذا مثال بعض القيود. على سبيل المثال، فقط 32-بت-كل-بكسل صور معتمدة؛ صور بتنسيقات غير ذلك تالفة بواسطة BitmapImageكائن أثناء عملية تغيير الحجم. وكذلك الصور المصدر يجب أن تكون الجميع بقعة صغيرة من الحجم الإطار المتجانب. كالتدريب إضافية، يمكنك إضافة وظائف إلى بمعالجة التنسيقات بكسل مختلفة وأحجام الملفات.

راجع أيضًا:

موارد أخرى

Schedulers مهمة

Advanced Topics (Task Parallel Library)