How to directly access the UI thread from the BackgroundWorker thread in WPF?
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();
            }
    
        }
    }


How to directly access the UI thread from the BackgroundWorker thread in WPF?
===

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();
            }
    
        }
    }

