如何直接从WPF BackgroundWorker的线程访问UI线程? [英] How to directly access the UI thread from the BackgroundWorker thread in WPF?

查看:336
本文介绍了如何直接从WPF BackgroundWorker的线程访问UI线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要创建WPF中的备份实用程序,并有关于线程 一般性的问题:



在该方法的 BackgroundWorker的。 DoWork的(),语句Message2.Text =...给出了错误,因为不同的线程拥有它的调用线程不能访问该对象。



有没有办法让我直接访问内backgroundWorker.DoWork(),即改变文本的UI线程在XAML文本框在这一点?或者,我需要所有的显示信息存储在一个内部变量,然后在 backgroundWorker.ProgressChanged显示它(),因为我曾与例如做?percentageFinished



XAML:



  <窗​​口x:类=TestCopyFiles111.Window1
的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/presentation
的xmlns:X =HTTP:// schemas.microsoft.com/winfx/2006/xaml
标题=窗口1HEIGHT =350WIDTH =525>
< D​​ockPanel中LastChildFill =真的Horizo​​ntalAlignment =左VerticalAlignment =评出的
保证金=10>

< StackPanel的方向=横向DockPanel.Dock =评出的>
<按钮X:NAME =Button_Start
的Horizo​​ntalAlignment =左
DockPanel.Dock =评出的
含量=开始复制
点击= Button_Start_Click
高度=25
保证金=0 0 5 0
WIDTH =200/>
<按钮X:NAME =Button_Cancel
的Horizo​​ntalAlignment =左
DockPanel.Dock =评出的
含量=取消
=单击 Button_Cancel_Click
高度=25
WIDTH =200/>
< / StackPanel的>

<进度X:NAME =进度
DockPanel.Dock =评出的
的Horizo​​ntalAlignment =左
保证金=0 10 0 0
高度=23
WIDTH =405
最短=0
最大=100
/>

< TextBlock的DockPanel.Dock =评出的X:名称=消息保证金=10 0 0 0/>
< TextBlock的DockPanel.Dock =评出的X:NAME =CurrentFileCopying保证金=0 10 0 0/>
< TextBlock的DockPanel.Dock =评出的X:名称=消息2保证金=0 10 0 0/>
< / DockPanel中>
< /窗GT;



后台代码:



 使用System.Windows; 
使用System.ComponentModel;
使用的System.Threading;
:使用System.IO;
使用System.Collections.Generic;
使用系统;

命名空间TestCopyFiles111
{
公共部分类窗口1:窗口
{
私人的BackgroundWorker BackgroundWorker的;

浮动percentageFinished = 0;
私人INT totalFilesToCopy = 0;
INT filesCopied = 0;

串currentPathAndFileName;

私人列表< CopyFileTask> copyFileTasks =新的List< CopyFileTask>();
私有列表<串GT; foldersToCreate =新的List<串GT;();

公共窗口1()
{
的InitializeComponent();
Button_Cancel.IsEnabled = FALSE;
Button_Start.IsEnabled = TRUE;
ProgressBar.Visibility = Visibility.Collapsed;

}

私人无效Button_Start_Click(对象发件人,RoutedEventArgs E)
{
Button_Cancel.IsEnabled = TRUE;
BackgroundWorker的=新的BackgroundWorker();
backgroundWorker.WorkerReportsProgress = TRUE;
backgroundWorker.WorkerSupportsCancellation = TRUE;
ProgressBar.Visibility = Visibility.Visible;

AddFilesFromFolder(@C:\test,@C:\test2);

Message.Text =正在准备拷贝...;

MakeSureAllDirectoriesExist();

CopyAllFiles();

}


无效AddFilesFromFolder(字符串sourceFolder,串destFolder)
{
如果(!Directory.Exists(destFolder))
Directory.CreateDirectory(destFolder);
的String []文件= Directory.GetFiles(sourceFolder);
的foreach(在文件中字符串的文件)
{
字符串名称= Path.GetFileName(文件);
串DEST = Path.Combine(destFolder,名);
copyFileTasks.Add(新CopyFileTask(文件,DEST));
totalFilesToCopy ++;
}
的String []文件夹= Directory.GetDirectories(sourceFolder);
的foreach(在文件夹中的文件夹弦)
{
字符串名称= Path.GetFileName(文件夹);
串DEST = Path.Combine(destFolder,名);
foldersToCreate.Add(DEST);
AddFilesFromFolder(文件夹,DEST);
}
}

无效MakeSureAllDirectoriesExist()
{
的foreach(在foldersToCreate VAR folderToCreate)
{
如果(! Directory.Exists(folderToCreate))
Directory.CreateDirectory(folderToCreate);
}
}

无效CopyAllFiles()
{
BackgroundWorker的=新的BackgroundWorker();
backgroundWorker.WorkerReportsProgress = TRUE;
backgroundWorker.WorkerSupportsCancellation = TRUE;

backgroundWorker.DoWork + =(S,参数)=>
{
filesCopied = 0;
的foreach(在copyFileTasks VAR copyFileTask)
{
如果(backgroundWorker.CancellationPending)
{
args.Cancel = TRUE;
的回报;
}

的DateTime sourceFileLastWriteTime = File.GetLastWriteTime(copyFileTask.SourceFile);
的DateTime targetFileLastWriteTime = File.GetLastWriteTime(copyFileTask.TargetFile);

如果(sourceFileLastWriteTime = targetFileLastWriteTime!)
{
Message2.Text =日期是不一样的;
}
,否则
{
Message2.Text =日期是相同的;
}

如果
File.Copy(copyFileTask.SourceFile,copyFileTask.TargetFile)(File.Exists(copyFileTask.TargetFile)!);

currentPathAndFileName = copyFileTask.SourceFile;

UpdatePercentageFinished();
backgroundWorker.ReportProgress((INT)percentageFinished);

filesCopied ++;
}

};

backgroundWorker.ProgressChanged + =(S,参数)=>
{
percentageFinished = args.ProgressPercentage;
ProgressBar.Value = percentageFinished;
Message.Text = percentageFinished +说完%;
CurrentFileCopying.Text = currentPathAndFileName;
};

backgroundWorker.RunWorkerCompleted + =(S,参数)=>
{
Button_Start.IsEnabled = TRUE;
Button_Cancel.IsEnabled = FALSE;
ProgressBar.Value = 0;
UpdatePercentageFinished();
CurrentFileCopying.Text =;

如果(percentageFinished< 100)
{
Message.Text =的String.Format(取消了在{0:0}%完成,percentageFinished);
}
,否则
{
Message.Text =所有文件复制。
}
};

backgroundWorker.RunWorkerAsync();
}

无效UpdatePercentageFinished()
{
percentageFinished =(filesCopied /(浮点)totalFilesToCopy)* 100F;
}


类CopyFileTask
{
公共字符串的SourceFile {搞定;组; }
公共字符串的TargetFile {搞定;组; }
公共CopyFileTask(字符串的资源文件,字符串的TargetFile)
{
的SourceFile =的资源文件;
的TargetFile =的TargetFile;
}
}

私人无效Button_Cancel_Click(对象发件人,RoutedEventArgs E)
{
backgroundWorker.CancelAsync();
}

}
}


解决方案

你有没有看使用Dispatcher.Invoke?

  Dispatcher.Invoke(新动作(() => {Button_Start.Content = i.ToString();})); 



或者,如果你想要的东西异步发生使用的BeginInvoke。


I'm creating a backup utility in WPF and have a general question about threading:

In the method backgroundWorker.DoWork(), the statement Message2.Text = "..." gives the error "The calling thread cannot access this object because a different thread owns it.".

Is there no way for me to directly access the UI thread within backgroundWorker.DoWork(), i.e. change text in a XAML TextBox at that point? Or do I need to store all display information in an internal variable, and then display it in backgroundWorker.ProgressChanged(), as I had to do with e.g. percentageFinished?

XAML:

<Window x:Class="TestCopyFiles111.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1"  Height="350" Width="525">
    <DockPanel LastChildFill="True" HorizontalAlignment="Left" VerticalAlignment="Top"
                Margin="10">

        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
            <Button x:Name="Button_Start" 
                    HorizontalAlignment="Left"  
                    DockPanel.Dock="Top" 
                    Content="Start Copying" 
                    Click="Button_Start_Click" 
                    Height="25" 
                    Margin="0 0 5 0"
                    Width="200"/>
            <Button x:Name="Button_Cancel" 
                    HorizontalAlignment="Left"  
                    DockPanel.Dock="Top" 
                    Content="Cancel" 
                    Click="Button_Cancel_Click" 
                    Height="25" 
                    Width="200"/>
        </StackPanel>

        <ProgressBar x:Name="ProgressBar"
                     DockPanel.Dock="Top" 
                     HorizontalAlignment="Left"
                    Margin="0 10 0 0"
                    Height="23"
                     Width="405"
                     Minimum="0"
                     Maximum="100"
                     />

        <TextBlock DockPanel.Dock="Top" x:Name="Message" Margin="0 10 0 0"/>
        <TextBlock DockPanel.Dock="Top" x:Name="CurrentFileCopying" Margin="0 10 0 0"/>
        <TextBlock DockPanel.Dock="Top" x:Name="Message2" Margin="0 10 0 0"/>
    </DockPanel>
</Window>

code-behind:

using System.Windows;
using System.ComponentModel;
using System.Threading;
using System.IO;
using System.Collections.Generic;
using System;

namespace TestCopyFiles111
{
    public partial class Window1 : Window
    {
        private BackgroundWorker backgroundWorker;

        float percentageFinished = 0;
        private int totalFilesToCopy = 0;
        int filesCopied = 0;

        string currentPathAndFileName;

        private List<CopyFileTask> copyFileTasks = new List<CopyFileTask>();
        private List<string> foldersToCreate = new List<string>();

        public Window1()
        {
            InitializeComponent();
            Button_Cancel.IsEnabled = false;
            Button_Start.IsEnabled = true;
            ProgressBar.Visibility = Visibility.Collapsed;

        }

        private void Button_Start_Click(object sender, RoutedEventArgs e)
        {
            Button_Cancel.IsEnabled = true;
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;
            ProgressBar.Visibility = Visibility.Visible;

            AddFilesFromFolder(@"c:\test", @"C:\test2");

            Message.Text = "Preparing to copy...";

            MakeSureAllDirectoriesExist();

            CopyAllFiles();

        }


        void AddFilesFromFolder(string sourceFolder, string destFolder)
        {
            if (!Directory.Exists(destFolder))
                Directory.CreateDirectory(destFolder);
            string[] files = Directory.GetFiles(sourceFolder);
            foreach (string file in files)
            {
                string name = Path.GetFileName(file);
                string dest = Path.Combine(destFolder, name);
                copyFileTasks.Add(new CopyFileTask(file, dest));
                totalFilesToCopy++;
            }
            string[] folders = Directory.GetDirectories(sourceFolder);
            foreach (string folder in folders)
            {
                string name = Path.GetFileName(folder);
                string dest = Path.Combine(destFolder, name);
                foldersToCreate.Add(dest);
                AddFilesFromFolder(folder, dest);
            }
        }

        void MakeSureAllDirectoriesExist()
        {
            foreach (var folderToCreate in foldersToCreate)
            {
                if (!Directory.Exists(folderToCreate))
                    Directory.CreateDirectory(folderToCreate);
            }
        }

        void CopyAllFiles()
        {
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;

            backgroundWorker.DoWork += (s, args) =>
            {
                filesCopied = 0;
                foreach (var copyFileTask in copyFileTasks)
                {
                    if (backgroundWorker.CancellationPending)
                    {
                        args.Cancel = true;
                        return;
                    }

                    DateTime sourceFileLastWriteTime = File.GetLastWriteTime(copyFileTask.SourceFile);
                    DateTime targetFileLastWriteTime = File.GetLastWriteTime(copyFileTask.TargetFile);

                    if (sourceFileLastWriteTime != targetFileLastWriteTime)
                    {
                        Message2.Text = "dates are not the same";
                    }
                    else
                    {
                        Message2.Text = "dates are the same";
                    }

                    if (!File.Exists(copyFileTask.TargetFile))
                        File.Copy(copyFileTask.SourceFile, copyFileTask.TargetFile);

                    currentPathAndFileName = copyFileTask.SourceFile;

                    UpdatePercentageFinished();
                    backgroundWorker.ReportProgress((int)percentageFinished);

                    filesCopied++;
                }

            };

            backgroundWorker.ProgressChanged += (s, args) =>
            {
                percentageFinished = args.ProgressPercentage;
                ProgressBar.Value = percentageFinished;
                Message.Text = percentageFinished + "% finished";
                CurrentFileCopying.Text = currentPathAndFileName;
            };

            backgroundWorker.RunWorkerCompleted += (s, args) =>
            {
                Button_Start.IsEnabled = true;
                Button_Cancel.IsEnabled = false;
                ProgressBar.Value = 0;
                UpdatePercentageFinished();
                CurrentFileCopying.Text = "";

                if (percentageFinished < 100)
                {
                    Message.Text = String.Format("cancelled at {0:0}% finished", percentageFinished);
                }
                else
                {
                    Message.Text = "All files copied.";
                }
            };

            backgroundWorker.RunWorkerAsync();
        }

        void UpdatePercentageFinished()
        {
            percentageFinished = (filesCopied / (float)totalFilesToCopy) * 100f;
        }


        class CopyFileTask
        {
            public string SourceFile { get; set; }
            public string TargetFile { get; set; }
            public CopyFileTask(string sourceFile, string targetFile)
            {
                SourceFile = sourceFile;
                TargetFile = targetFile;
            }
        }

        private void Button_Cancel_Click(object sender, RoutedEventArgs e)
        {
            backgroundWorker.CancelAsync();
        }

    }
}

解决方案

Have you looked at using Dispatcher.Invoke?

Dispatcher.Invoke(new Action(() => { Button_Start.Content = i.ToString(); }));

Or use BeginInvoke if you want something to happen asynchronously.

这篇关于如何直接从WPF BackgroundWorker的线程访问UI线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆