Не удается отобразить загрузчик GIF в WPF во время выполнения операции базы данных

Привет я пытаюсь отобразить изображение GIf при выполнении некоторых трудоемких операций.

Я попытался с помощью следующего кода.. я могу видеть окно загрузки, но анимация изображения GIF не работает.. при поиске решения я нашел метод для обновления пользовательского интерфейса, пока он зависает с помощью фоновой функции. но все равно это не работает. Вот мой код XAML окна загрузчика:

<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>

Я пытаюсь отобразить это окно в окне другого элемента управления пользователя, в котором есть кнопка, которая будет выполнять некоторые операции с БД при нажатии здесь, это мой код кнопки

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

вот способ принудительно обновить пользовательский интерфейс при заморозке

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

И фоновый рабочий код выглядит следующим образом

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

пожалуйста, предложите мне способ выполнить мою задачу.. Спасибо

1 ответ

Решение

Вы используете BackgroundWorker неправильно. Ты звонишь Dispatcher.InvokeAsync от DoWork метод, который фактически выполняет код в потоке пользовательского интерфейса, а не в фоновом потоке, следовательно, блокирует пользовательский интерфейс. Что вам нужно сделать, это найти способ фактически выполнить ваш трудоемкий код в фоновом режиме, а затем обновлять интерфейс только из RunWorkerCompleted когда работа сделана, или используйте ReportProgress если вам нужно обновить интерфейс во время выполнения.

Как: использовать фоновый рабочий

Кроме того, покажите окно загрузчика при запуске работника, как вы уже сделали, но вызовите метод, чтобы скрыть его от RunWorkerCompleted, который выполняется в потоке пользовательского интерфейса после завершения фонового потока, а не из DoWork метод.

Другие вопросы по тегам