简体   繁体   中英

C# WPF - Long Operation On Button Click

I have Button , which calls another method on click. The other method performs an operation which can take a long time... So I thought to create a Label which appears on the start of the operation and tells the user to wait, after the operation is complete, the Label will disappear. The only problem is that because the Button is a UI element (that is what I think the reason is), the calls to change the Label inside the Button click only activate after the Button click is complete... (so basically the Label was invisible before the click and cannot change during it, so it stays that way).

Here is my code:

private void SearchButtonActions()
{
        UI.InvokeA(() => lstFiles.ItemsSource = FDItems);
        bool SearchAndListing = false;
        //UI.InvokeA(() => lblWait.Height = double.NaN);
        //UI.InvokeA(() => lblWait.Visibility = Visibility.Visible);
        //UI.InvokeA(() => lblWait.Content = "Search Started...");
        int index = cbTypes.SelectedIndex;
        string selecteditem = cbSearchOption.SelectedItem.ToString();
        SearchAndListing = FD.Search(index, selecteditem);
        FDItems = new ObservableCollection<Item>(FD.Items);
        //UI.InvokeA(() => lblWait.Height = 0);
        //UI.InvokeA(() => lblWait.Visibility = Visibility.Hidden);
        //UI.InvokeA(() => lblWait.Content = "Search Ended.");
        if (SearchAndListing)
        {
            UI.InvokeA(() => lstFiles.ItemsSource = FDItems);
            UI.InvokeA(() => lblCount.Content = string.Format("Items: {0}", FDItems.Count));
        }
}

I am talking about the methods to change the lblWait ... btw: UI.Invoke - is a shortcut to Dispatcher.Current.InvokeAsync(Action)

I have tried using Tasks , BackGroundWorker , and changing the UI.Invoke to Invoke ( synchronically instead of asynchronically ), and all didn't work out...

Can someone help?

I came across this issue before and never gave much thought to it until now.

Your argument is correct the UI thread is currently running the Click method so it is busy and will not run any thing else.

even when using the dispatcher it is still performing the click method so the ui thread would pop the next delegate to run only when it's done.

So this wouldn't work :

   lbl.Visibility = Visibility.Visible;
   Thread.Sleep(3000);

And this wouldn't work :

    Dispatcher.Invoke(() => lbl.Visibility = Visibility.Visible);
    Dispatcher.Invoke(() => Thread.Sleep(3000));

What would work is dispatching the ui operations from a background thread.

XAML :

    <StackPanel>   
       <Button Click="Button_Click" Content="Click"/>
       <Label x:Name="lbl" Content="Label" Visibility="Hidden" Foreground="Red" FontSize="22" HorizontalAlignment="Center"/>
     </StackPanel>

CS :

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        await Dispatcher.InvokeAsync(() => 
        {
            Debug.WriteLine("Visibility");
            lbl.Visibility = Visibility.Visible;                
        });

        await Task.Run(() =>
        {
            return Dispatcher.InvokeAsync(() => Thread.Sleep(3000));
        });            
    }

FYI : your probably wondering why i do not propagate the Visibility value to the UI thread using the dispatcher. This is because each DispatcherObject ( our DependencyObject derived from DispatcherObject) propagates execution to it's associated Dispatcher.

  1. Show your "please wait label" as soon as you click the button.
  2. Execute your long operation: FD.Search(index, selecteditem); in an async Task.Run()
  3. Use ContinueWith() to hide the label once the long operation is complete.

     private void SearchButtonActions() { lblWait.Visibility = Visibility.Visible; Task.Run(() => { return FD.Search(index, selecteditem); }).ContinueWith((Task<bool> task) => { Dispatcher.Invoke(() => { FDItems = new ObservableCollection<Item>(FD.Items)); lblWait.Visibility = Visibility.Hidden; }); }); } 

If you need the result of FD.Search() somewhere in the ContinueWith() block, use task.Result to retrieve it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM