0

Hi I am trying to Display GIf Image on some Time Consuming operations execution.

I tried with following code.. am able to see the load window but animation of gif image is not working.. when searched for solution I found Method to Update UI while its freezed by background function. but still it is not working. Here is my Loader Window XAML Code:

<Window x:Class="project1.Views.loader" 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"              
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
  xmlns:winForms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
  xmlns:gif="http://wpfanimatedgif.codeplex.com"
  gif:ImageBehavior.AnimateInDesignMode="True"
  Title="Loading" Height="180" Width="461" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" WindowStyle="SingleBorderWindow" Loaded="Window_Loaded">
 <StackPanel Name="LoadingData" Background="White" >
    <Label x:Name="lblprogressmessage" x:FieldModifier="public" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,35,0,10" Content="" Foreground="#FF1E8ED4" FontSize="14"></Label>
    <Image x:Name="imggif" gif:ImageBehavior.RepeatBehavior="Forever"  gif:ImageBehavior.AnimatedSource="pack://application:,,,/project1;component/Images/ajaxloader.gif" Height="50px" Width="60px"/>
 </StackPanel>
</Window>

Am Trying to display this window in Another User control window which is having button which will do some db operation when clicked here is my button code

loaderWindow ld = new loaderWindow // object to show loader window
Sample ViewModel = new Sample();

private void btn_Click(object sender, RoutedEventArgs e)
{
   try
    {          
      SampleEntityManager objem = new SampleEntityManager ();
      using (var dbContext = Database1.getDBContext())
      {
        if(objem .checkFundExist(dbContext,Guid.Parse(cbx1SelectedValue.ToString()), Guid.Parse(cbx2.SelectedValue.ToString()), int.Parse(cbx3.SelectedValue.ToString())) == false)
          {
            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = true;
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            ForceUIToUpdate();
            bw.RunWorkerAsync();
            ld.lblprogressmessage.Content = "Creating Fund for Year "+cbx1.Text +" Please Wait. . .";

           *ld.Show();* // calling show method to display loader window
          }
         else
          {
            MessageBox.Show("Fund Has Already Been Created", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
           }
         }
      }       
      catch (Exception es)
       {
         MessageBox.Show("Invalid Opertaion try again.If Problem Persists Contact Support", "Error", MessageBoxButton.OK, MessageBoxImage.Information);
       }
 }

here is method to forcefully Update UI on freeze

    // method to update UI
    public static void ForceUIToUpdate()
    {
        DispatcherFrame frame = new DispatcherFrame();

        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, new DispatcherOperationCallback(delegate (object parameter)
        {
            frame.Continue = false;
            return null;
        }), null);

        Dispatcher.PushFrame(frame);
    }

And background worker code as follows

  private void bw_DoWork(object sender, DoWorkEventArgs e)
  {
        BackgroundWorker worker = sender as BackgroundWorker;
        if ((worker.CancellationPending == true))
        {
            e.Cancel = true;
        }
        else
        {
            // Perform a time consuming operation and report progress.

            this.Dispatcher.InvokeAsync((Action)(() =>
            {
               // Time Consuming Database method which will set Fund entry Field for all the employess in Union
                ViewModel .CreateFund(cbx1.SelectedItem, cbx2.SelectedItem,cbx3.SelectedValue.ToString(), txt_desc.Text);
                cbx1.SelectedIndex = -1;
                cbx2.SelectedIndex = -1;
                **ld.Hide();** // calling Hide Method close Loader window once database opertaion completed
            }), System.Windows.Threading.DispatcherPriority.Background);
        }
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        BackgroundWorker worker = (BackgroundWorker)sender;
        if ((e.Cancelled == true))
        {
            ld.lblprogressmessage.Content = "Cancelled !";
        }
        else if (!(e.Error == null))
        {
            ld.lblprogressmessage.Content = ("Error  : " + e.Error.Message);
        }
        else
        {
            if (worker.WorkerSupportsCancellation == true)
            {
                worker.CancelAsync();
            }
        }
    }

please suggest me a way to complete my task.. Thank you

1 Answers1

1

You are using the BackgroundWorker wrong. You are calling Dispatcher.InvokeAsync from the DoWork method, which is actually executing the code on the UI thread, not the background thread, hence blocking the UI. What you need to do is find a way to actually execute your time-consuming code in the background, and then update the UI only from RunWorkerCompleted when the work is done, or use ReportProgress if you need to update the UI during the execution.

How to: Use a Background Worker

Also, show the loader window when you are starting the worker, like you already did, but call the method to hide it from the RunWorkerCompleted, which is executing on the UI thread after the backgroud thread is finished, not from the DoWork method.

Nemanja Banda
  • 796
  • 2
  • 14
  • 23
  • Hi @Nemanja Banda I Tried Removing Dispatcher.invokeAsync but it is showing this Error "The calling thread cannot access this object because a different thread owns it." On the ViewModel .CreateFund() Line.. is there any other way to make it run on background – supreeth mr Feb 02 '16 at 12:03
  • 1
    You are trying to access the UI object from the background thread, which is not allowed in WPF. What you can do is create some class that will hold all the information, fill it with data that you need from the UI, and then pass it to `BackgroudWorker` to do all the work with the data, without accessing the UI... – Nemanja Banda Feb 02 '16 at 12:18
  • Thanks @Nemanja Banda I tried creating another class for taking inputs and its working.. – supreeth mr Feb 02 '16 at 13:24