Остановка и запуск задач с помощью CancellationTokenSource - PullRequest
0 голосов
/ 20 марта 2019

это просто упрощенная версия того, что я пытаюсь сделать

public partial class MainWindow : Window
{
    private CancellationTokenSource tokenSource = new CancellationTokenSource();

    public MainWindow()
    {
        InitializeComponent();
        PrintButtonText("None");
    }

    private void PrintButtonText(string buttonText)
    {
        Console.WriteLine("Update!");
        Task.Factory.StartNew(() =>
        {
            while (!tokenSource.Token.IsCancellationRequested)
            {
                Console.WriteLine("Button Pressed Text: " + buttonText);
            }
        }, tokenSource.Token);
    }

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
        tokenSource.Cancel();
        PrintButtonText("Button1");
    }

    private void Button2_Click(object sender, RoutedEventArgs e)
    {
        tokenSource.Cancel();
        PrintButtonText("Button2");
    }
}

После того, как я

tokenSource.Cancel();
PrintButtonText("Button1");

Невозможно снова запустить задачу и продолжить печатать мойлиния.Мне нужно, чтобы это работало так для моей программы.

Я хочу остановить поток и запустить его снова с некоторыми другими параметрами.Как мне этого добиться?спасибо

РЕДАКТИРОВАТЬ :

Поскольку у меня не было решения с моей упрощенной версией, вот полный код и то, что я пытаюсь сделать.По сути, в окне wpf рендеринг камеры начинается при запуске.Есть кнопка, чтобы начать сохранение в файл, но для того, чтобы сохранить, мне нужно обновить конфигурацию и снова запустить «конвейер».

public partial class MainWindow : Window
{
    private Pipeline pipeline = new Pipeline(); // Create and config the pipeline to sream color and depth frames.
    private CancellationTokenSource tokenSource = new CancellationTokenSource();

    private bool saveDataToFile = false;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        Config cfg = SetupConfig(false);
        PipelineProfile pp = pipeline.Start(cfg);
        StartRenderFrames(pp);
    }

    private void StartRenderFrames(PipelineProfile pp)
    {
        Colorizer colorizer = new Colorizer(); // The colorizer processing block used to visualize the depth frames.

        // Allocate bitmaps for rendring. Since the sample aligns the depth frames to the color frames, both of the images will have the color resolution
        using (var p = pp.GetStream(Stream.Color) as VideoStreamProfile)
        {
            imgColor.Source = new WriteableBitmap(p.Width, p.Height, 96d, 96d, PixelFormats.Rgb24, null);
            imgDepth.Source = new WriteableBitmap(p.Width, p.Height, 96d, 96d, PixelFormats.Rgb24, null);
        }
        Action<VideoFrame> updateColor = UpdateImage(imgColor);
        Action<VideoFrame> updateDepth = UpdateImage(imgDepth);

        Task.Factory.StartNew(() =>
        {
            while (!tokenSource.Token.IsCancellationRequested)
            {
                // Wait for the next available FrameSet
                using (var frames = pipeline.WaitForFrames())
                {
                    var colorFrame = frames.ColorFrame.DisposeWith(frames);
                    var depthFrame = frames.DepthFrame.DisposeWith(frames);

                    // We colorize the depth frame for visualization purposes, .
                    var colorizedDepth = colorizer.Process(depthFrame).DisposeWith(frames);

                    // Render the frames.
                    Dispatcher.Invoke(DispatcherPriority.Render, updateDepth, colorizedDepth);
                    Dispatcher.Invoke(DispatcherPriority.Render, updateColor, colorFrame);
                }
            }
        }, tokenSource.Token);
    }

    private Config SetupConfig(bool saveDepthFile)
    {
        Config cfg = new Config();
        cfg.EnableStream(Stream.Depth, 640, 480, framerate: 15);
        cfg.EnableStream(Stream.Color, 640, 480, format: Format.Rgb8, framerate: 15);
        if (saveDepthFile)
        {
            cfg.EnableRecordToFile(@"C:\temp\My_test111.bag");
        }
        return cfg;
    }

    static Action<VideoFrame> UpdateImage(Image img)
    {
        var wbmp = img.Source as WriteableBitmap;
        return new Action<VideoFrame>(frame =>
        {
            using (frame)
            {
                var rect = new Int32Rect(0, 0, frame.Width, frame.Height);
                wbmp.WritePixels(rect, frame.Data, frame.Stride * frame.Height, frame.Stride);
            }
        });
    }

    private void StartSaving_Button_Click(object sender, RoutedEventArgs e)
    {
        tokenSource.Cancel();
        pipeline.Stop();
        // This is where I have a problem. Rendering thread does not stop before I want to start again.
        Config cfg = SetupConfig(true);
        PipelineProfile pp = pipeline.Start(cfg);
        StartRenderFrames(pp);
    }
}

1 Ответ

0 голосов
/ 21 марта 2019

Вы должны использовать Microsoft Reactive Framework (он же Rx) - NuGet System.Reactive.Windows.Forms и добавить using System.Reactive.Linq; - тогда вы можете сделать это:

    private void Form1_Load(object sender, EventArgs e)
    {
        IObservable<string> button1Clicks =
            Observable
                .FromEventPattern<EventHandler, EventArgs>(h => button1.Click += h, h => button1.Click -= h)
                .Select(ep => "Button1");

        IObservable<string> button2Clicks =
            Observable
                .FromEventPattern<EventHandler, EventArgs>(h => button2.Click += h, h => button2.Click -= h)
                .Select(ep => "Button2");

        IDisposable subscription =
            button1Clicks
                .Merge(button2Clicks)
                .StartWith("None")
                .Select(x => Observable.Timer(TimeSpan.Zero, TimeSpan.FromMilliseconds(500.0)).Select(n => x))
                .Switch()
                .ObserveOn(this)
                .Subscribe(x => Console.WriteLine(x));
    }

Это весь код, необходимый для того, чтобы вы работали.

Единственное, что вам нужно сделать, это переместить subscription в поле private и затем просто позвонить subscription.Dispose(), чтобы отключить все это.

Это намного проще, чем возиться с токенами отмены.

...