WPF UserControl run button click async

hossein tavakoli 471 Reputation points
2022-10-12T20:33:48.36+00:00

Hi dears,

I have a WPF UserControl contains a button and a progress bar.
I want to show progress bar when user click on button and hide it after click function finished.
I have a code but when I click on usercontrol it throw an exception 'The calling thread cannot access this object because a different thread owns it'.

my UserControl :

<Grid Margin="0">  
        <Button x:Name="EntryBottun" Margin="0" Cursor="Hand" Click="btnButton_Click" Content="Click Me..." />  
        <ProgressBar x:Name="ProgressButton" IsIndeterminate="True" Opacity="0.5" Margin="0" Visibility="Hidden"/>  
    </Grid>  
  
-------------------------------------  

        public event Action<object, string> Click;  
        private async void btnButton_Click(object sender, RoutedEventArgs e)  
        {  
            if (Click != null)  
            {  
                ProgressButton.Visibility = Visibility.Visible;  
  
                if (Click != null)  
                    ProgressButton.Visibility = await ClickEvent();  
                else   
                    ProgressButton.Visibility=Visibility.Hidden;  
            }  
        }  
  
        private Task<Visibility> ClickEvent()  
        {  
            return Task.Run(() =>  
            {  
  
                if (Click != null)  
                    Click(this, btnButton.Content);  
  
                return Visibility.Hidden;  
  
            });  
        }  

my form :

<usercontrols:ButtonProgress x:Name="btnLogin" Content="Login" Margin="10" Click="btnLogin_Click" />  
  
--------------------------  
  
private async void btnLogin_Click(object arg1, string arg2)  
        {  
            if (txtPassword.Password == string.Empty || txtUsername.Text == string.Empty)  
            {  
                lblError.Content = "Please check username and password";  
                return;  
            }  
        }  
Developer technologies Windows Presentation Foundation
Developer technologies XAML
Developer technologies C#
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Michael Taylor 60,161 Reputation points
    2022-10-12T21:16:14.743+00:00

    That's because of your ClickEvent method. When you use Task.Run to run some code, that code is run on a thread pool thread (logically, but you cannot rely on that behavior). Therefore you cannot access any UI elements inside this method. The only way to interact with the UI is on the thread that created it, hence the error. You cannot "asynchronously" update the UI. All UI calls must occur on the UI thread.

    In your very specific case there is no benefit in using async at all. But a more realistic example does make sense.

       private async void btnButton_Click(object sender, RoutedEventArgs e)  
                {  
                    if (Click != null)  
                    {  
                        ProgressButton.Visibility = Visibility.Visible;  
         
                        await DoWorkAsync();  
                        ProgressButton.Visibility = Visibility.Hidden;  
                    }  
                }  
             
                private Task DoWorkAsync ()  
                {  
                    return Task.Run(() =>  
                    {   
                       //Do non UI work here                  
                    });  
                }  
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.