Click here to Skip to main content
15,881,815 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi All,
I am trying to create a
Busy indicator
while running the long tasks,but
Busy indicator
is not showing
i am using the below code

XAML Code is :
XML
<UserControl x:Class="ELT_Data_Extractor.View.DataBaseBrowser"
             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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
             xmlns:viewmodel="clr-namespace:ELT_Data_Extractor.ViewModel"
             
             mc:Ignorable="d" 
             d:DesignHeight="600" d:DesignWidth="576">
    <UserControl.Resources>
        <viewmodel:ExtractInfoVM x:Key="vm"></viewmodel:ExtractInfoVM>

    </UserControl.Resources>
    <UserControl.DataContext>
        <viewmodel:ExtractInfoVM></viewmodel:ExtractInfoVM>
    </UserControl.DataContext>

    <Grid Height="540">
        <Grid.RowDefinitions>
            <RowDefinition Height="400" />
            <RowDefinition Height="5" />
            <RowDefinition Height="102" />
            <RowDefinition Height="53*" />
            
            
            

        </Grid.RowDefinitions>
        <StackPanel DataContext="{Binding Source={StaticResource vm}}">
            <Grid Height="400">
                <Grid.RowDefinitions>
                    <RowDefinition Height="33*" />
                    <RowDefinition Height="33*" />
                    <RowDefinition Height="33*" />
                    <RowDefinition Height="89*" />
                    <RowDefinition Height="41*" />
                    <RowDefinition Height="41*" />
                    <RowDefinition Height="41*" />
                    <RowDefinition Height="18*" />
                    <RowDefinition Height="35*" />
                    <RowDefinition Height="35*" />

                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="11" />
                    <ColumnDefinition Width="94" />
                    <ColumnDefinition Width="178*" />
                    <ColumnDefinition Width="261*" />
                    <ColumnDefinition Width="10*" />

                </Grid.ColumnDefinitions>
                
                
                
                <Label Content="Vendor:" Grid.Column="1"  Height="25" HorizontalAlignment="Stretch" Name="lblVendor" VerticalAlignment="Center" Grid.ColumnSpan="3" Margin="0,4"  />
                <ComboBox ItemsSource="{Binding VendorList}"  
                  SelectedValue="{Binding SelectedVendor}"  
                  Grid.Column="2" Height="23" HorizontalAlignment="Stretch" Name="cboVendor" VerticalAlignment="Center" Grid.ColumnSpan="2" Margin="0,5">
                    
                </ComboBox>

                <Label Content="Server:" Grid.Column="1"  Height="25" HorizontalAlignment="Stretch" Name="lblServer" VerticalAlignment="Center" Grid.ColumnSpan="3" Margin="0,1,0,7" Grid.Row="1" />
                <ComboBox Grid.Column="2" ItemsSource="{Binding Servers}"  
                  SelectedValue="{Binding SelectedServer}"
                  Height="23" HorizontalAlignment="Stretch" Name="cboServer" VerticalAlignment="Center" Grid.ColumnSpan="2" Margin="0,3,0,7" Grid.Row="1" />
               
                <Label Content="DataBase:" Grid.Column="1" Grid.Row="1" Height="25" HorizontalAlignment="Stretch" Name="lblDataBase" VerticalAlignment="Center" Grid.ColumnSpan="3" Margin="0,32,0,9" Grid.RowSpan="2" />
                <ComboBox Grid.Column="2" ItemsSource="{Binding Databases}"
                          SelectedValue="{Binding SelectedDatabase}"
                          Grid.Row="2" Height="23" HorizontalAlignment="Stretch" Name="cboDatabase" VerticalAlignment="Center" Margin="0,1,0,9" Grid.ColumnSpan="2" />
              
                <Label Content="Analysis:" Grid.Column="1" Grid.Row="2" Height="25" HorizontalAlignment="Stretch" Name="lblAnalysis" VerticalAlignment="Center" Grid.ColumnSpan="3" Margin="0,26,0,71" Grid.RowSpan="2" />
                <ComboBox Grid.Column="2" ItemsSource="{Binding Analysis}" 
                          SelectedValue="{Binding SelectedAnalasis}"
                        Grid.Row="2" Height="23" HorizontalAlignment="Stretch" Name="cboAnalysis"  VerticalAlignment="Center" Margin="0,29,0,70" Grid.RowSpan="2" Grid.ColumnSpan="2" />

                <TextBox Background="#FFEFECCD" Text="{Binding AnalysisInfo}"  Grid.Column="2" Grid.Row="3" HorizontalAlignment="Stretch"  Name="txtDesciptoin" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" TextWrapping="NoWrap" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" BorderThickness="2" Margin="0,24,0,0" Grid.ColumnSpan="2" />

                <Label Content="Perspective:" Grid.Column="1" Grid.Row="4" Height="25" HorizontalAlignment="Stretch" Name="lblperspective" VerticalAlignment="Center" Grid.ColumnSpan="3" Margin="0,8" />
                <ComboBox Grid.Column="2" ItemsSource="{Binding PerspectiveCodesList}" 
                          SelectedValue="{Binding SelectedPerspective}" 
                         Grid.Row="4" Height="23" HorizontalAlignment="Left" Name="cboPerspective" VerticalAlignment="Center" Width="186" Grid.ColumnSpan="2" Margin="0,9" />

                <Label Content="Level:" Grid.Column="1" Grid.Row="5" Height="25" HorizontalAlignment="Stretch" Name="lblLevel" VerticalAlignment="Center" Grid.ColumnSpan="3" Margin="0,8" />
                <!--IsEnabled="{Binding ElementName=cboVendor,Path=IsReadOnly}"-->
                <ComboBox Grid.Column="2" ItemsSource="{Binding LevelList}" 
                          SelectedValue="{Binding SelectedLevel}"  
                          DisplayMemberPath="LevelDescription"
                         Grid.Row="5" Height="23" HorizontalAlignment="Left" Name="cboLevel" VerticalAlignment="Center"  Width="186" Grid.ColumnSpan="2" Margin="0,9" />

                <Label Content="Loss Case:" Grid.Column="1" Grid.Row="6" Height="25" HorizontalAlignment="Stretch" Name="lblLossCase" VerticalAlignment="Center" Grid.ColumnSpan="3" Margin="0,8" />
                <ComboBox Grid.Column="2"  
                          Grid.Row="6" Height="23" HorizontalAlignment="Left" Name="cboLosscase" VerticalAlignment="Center" Width="186" Grid.ColumnSpan="2" Margin="0,9">
                    <ComboBox.Style>
                        <Style>
                            <Style.Triggers>
                                <DataTrigger 
                     Binding ="{Binding ElementName=cboVendor, Path=SelectedIndex}" 
                     Value="0">
                                    <Setter Property="ComboBox.IsEnabled" Value="false"/>
                                </DataTrigger>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding ElementName=cboVendor, Path=SelectedIndex}" Value="1" />
                                        
                                    </MultiDataTrigger.Conditions>
                                    <Setter Property="ComboBox.IsEnabled" Value="False" />
                                </MultiDataTrigger>
                            </Style.Triggers>
                        </Style>
                    </ComboBox.Style>
                </ComboBox>

                <Border BorderBrush="Silver" BorderThickness="1" Grid.Column="3" Grid.RowSpan="3" Grid.Row="4" HorizontalAlignment="left"  Name="border1" VerticalAlignment="Center" Width="257" Margin="17,11,0,3" Height="109">
                    <ListBox Name="lstReferenc" 
                             SelectedItem="{Binding Path=SelectedGranularity,UpdateSourceTrigger=PropertyChanged}" 
         ItemsSource="{Binding Granularitylist, NotifyOnSourceUpdated=True}" SelectionMode="Multiple" Margin="103,8,9,8" IsEnabled="{Binding Path=AllPropertiesValid}" >
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding DetailValue}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>

                        <ListBox.ItemContainerStyle>
                            <Style TargetType="{x:Type ListBoxItem}">

                               
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding IsSelected}" Value="True">
                                        <Setter Property="Background" Value="Red" />
                                    </DataTrigger>
                                </Style.Triggers>
                                <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
                            </Style>

                        </ListBox.ItemContainerStyle>

                    </ListBox>
                </Border>

                <Label Content="Granularity:" Grid.Column="3" Grid.Row="4" Height="25" HorizontalAlignment="Stretch" Margin="33,0,166,0" Name="label5" VerticalAlignment="Bottom"  />
                <Button Content="Select All"  Command="{Binding SelectAll}"
                        Grid.Column="3" Grid.Row="5" Height="23" HorizontalAlignment="Stretch" Margin="33,13,166,5" Name="btnSelectAll" VerticalAlignment="Center" Width="75" IsEnabled="{Binding Path=AllPropertiesValid}"  />
                <Button Content="Unselect All" Grid.Column="3" Grid.Row="6" Height="23" HorizontalAlignment="Stretch" Command="{Binding UnSelectAll}"
                        Name="btnUnselectAll" VerticalAlignment="Top" Width="75" Margin="33,8,166,0" IsEnabled="{Binding Path=AllPropertiesValid}" />

                <Label Content="File Name:" Grid.Column="1" Grid.Row="7" Height="25" HorizontalAlignment="Stretch" Name="label7" VerticalAlignment="Center" />
                <TextBox Grid.Row="7" Height="25" Name="txtName" Grid.Column="2" Text="{Binding FileName}" Grid.ColumnSpan="2" Margin="0,0,0,28" Grid.RowSpan="2" />

                <Label Content="Folder:" Grid.Column="1" Grid.Row="8" Height="25" HorizontalAlignment="Stretch" Name="label8" VerticalAlignment="Center" />
                <!--EJG comment: Bind Folder textbox to member property ("FilePath") in ExtractInfo object model (similar to FileName)-->
                <TextBox Grid.Row="8" Height="25" Name="txtPath" IsReadOnly="True" Grid.Column="2" Text="{Binding OutputPath,ValidatesOnDataErrors=True}" Grid.ColumnSpan="2" Margin="0,5" />
                <Button  Grid.Column="3" Content="(...)"  Command="{Binding FileBrowse}"
                         Grid.Row="8" HorizontalAlignment="Right" Name="btnBrowse" Width="40" VerticalAlignment="Center" Margin="0,7" />

                <Button Content="Generate" Command="{Binding GenerateReport}"
                        Grid.Column="3" Grid.Row="9" Height="25" HorizontalAlignment="Right" Name="btnGenerate" VerticalAlignment="Center" Width="100" Margin="0,5"  />
                <xctk:BusyIndicator IsBusy="{Binding BackgroundProcess}"  BusyContent="Extracting Data..."  >
                   
                </xctk:BusyIndicator>

            </Grid>
        </StackPanel>
        <GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" Margin="0,0,10,0" />
        <StackPanel Grid.Row="2" Grid.RowSpan="2" DataContext="{Binding Source={StaticResource vm}}" Margin="0,0,0,34">
            <DataGrid x:Name="grdfilelist" AutoGenerateColumns="False"  ItemsSource="{Binding ELTFileList}" Margin="10,2,8,51" Height="97" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Button  Margin="3" Command="{Binding DataContext.RemoveCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" 
                						CommandParameter="{Binding ConverterParameter=parameter}">
                                        <ToolTipService.ToolTip>
                                            <ToolTip Content="Remove File" />
                                        </ToolTipService.ToolTip>
                                        <Image Height="12" Width="12"  Stretch="Uniform" Source="/Images/Delete.PNG" />
                                    </Button>
                                </Grid>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn Header="FileName"  Binding="{Binding FileName}"/>
                    <DataGridTextColumn Header="Path" Binding="{Binding FilePath}" />
                </DataGrid.Columns>
            </DataGrid>

        </StackPanel>
    </Grid>
</UserControl>

My c# code is
C#
private bool _backgroundprocess;

public bool BackgroundProcess
{
	get { return _backgroundprocess; }
	set
	{
		if (value != _backgroundprocess)
		{
			_backgroundprocess = value;
			OnPropertyChanged("BackgroundProcess");
		}
	}
}

public ObservableCollection<lossextractor.extractinfo> ExportData()
{
	backgroundprocess = true;
///My code is here 

	backgroundprocess = false;
}


What I have tried:

i was tried to implement in the Mainwindow its working fine
Posted
Updated 1-Sep-17 9:01am
v2
Comments
Graeme_Grant 30-Aug-17 3:17am    
Great that you posted code but there is far too much here!

According to you XAML code, you have two (2) instances of your ViewModel set in three (3) locations.

Once here bound to the user control:
XML
<UserControl.DataContext>
    <viewmodel:ExtractInfoVM></viewmodel:ExtractInfoVM>
</UserControl.DataContext>

and here:
XML
<StackPanel DataContext="{Binding Source={StaticResource vm}}">

and here:
XML
<StackPanel Grid.Row="2" Grid.RowSpan="2" DataContext="{Binding Source={StaticResource vm}}" Margin="0,0,0,34">

Remove the last two instances and also this below and it should work:
XML
<UserControl.Resources>
	<viewmodel:ExtractInfoVM x:Key="vm"></viewmodel:ExtractInfoVM>
</UserControl.Resources>

Lastly, also check that you have not set the DataContext in the code-behind.

Update: Richard Deeming suggests to use a BackGroundWorker but these days, going forward, it is better to learn how to use Task-based Asynchronous Pattern (TAP)[^] as the BackGroundWorker is limited to a specific type of job.

Here is an example of a long running task with a IsBusy state flag. This example wraps a synchronous process and moves it off the UI thread to stop it blocking and run in the background. This is done using a TaskCompletionSource(TResult) Class (System.Threading.Tasks)[^]. I'm also using MvvmLight[^] for the RelayCommand, DispatherHelper, and ViewModelBase classes to keep the example code simple.

1. ViewModel:
C#
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using GalaSoft.MvvmLight.Threading;
using System.Threading.Tasks;

namespace LongRunningTask
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
            => ExecuteTaskCommand = new RelayCommand(
                () => busyTask = StartExport(),
                () => !isBusy);

        private Task busyTask;
        public RelayCommand ExecuteTaskCommand { get; }

        private bool isBusy;
        public bool IsBusy
        {
            get => isBusy;
            set => Set(ref isBusy, value);
        }

        private async Task StartExport()
        {
            try
            {
                IsBusy = true;
                bool success = await ExportDataAsync().ConfigureAwait(false);
            }
            // ensure that no matter what, the busy state is cleared even if there were errors
            finally
            {
                // make sure we're on the UI thread...
                DispatcherHelper.CheckBeginInvokeOnUI(() =>
                {
                    IsBusy = false;
                    ExecuteTaskCommand.RaiseCanExecuteChanged();
                });
            }
        }

        private Task<bool> ExportDataAsync()
        {
            var tcs = new TaskCompletionSource<bool>();

            Task.Run(async () =>
            {
                // Do long running synchronous work here...
                await Task.Delay(3000).ConfigureAwait(false); // simulate a 3 second task

                // signal success!
                tcs.SetResult(true);
            }).ConfigureAwait(false);

            return tcs.Task;
        }
    }
}

2. MainWindow code-behind to initialze the DispatherHelper:
C#
using GalaSoft.MvvmLight.Threading;
using System.Windows;

namespace LongRunningTask
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DispatcherHelper.Initialize();
        }
    }
}

3. The MainWindow XAML:
XML
<Window
    x:Class="LongRunningTask.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    mc:Ignorable="d"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:local="clr-namespace:LongRunningTask"

    Title="CODE PROJECT  -   LONG RUNNING TASK"
    Height="350" Width="525" WindowStartupLocation="CenterScreen">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.Resources>
            <Style TargetType="Grid">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsBusy}" Value="True">
                        <Setter Property="Background" Value="Red"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Resources>

        <Button Content="Start Task" Padding="10,5"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Command="{Binding ExecuteTaskCommand}"/>
    </Grid>

</Window>

When the button is clicked, the background of the form is changed to Red and the button is disabled. This is to indicate the busy state. Once completed, the background and button return to their normal states.
 
Share this answer
 
v2
Comments
Ram349 30-Aug-17 7:11am    
Hi Greeme_Grant,
Thanks for replying my post,i added below code in my window.xaml.cs
DataContext = ELT_Data_Extractor.ViewModel.ExtractInfoVM();
if any thing wrong could you please provide datacontext code in code behind
Thank you very much
Graeme_Grant 30-Aug-17 7:46am    
Why? Only set the DataContext once in one place, not in 3 - you now have 3 unique instances of the ViewModel. To fix, remove that code and make the changes as mentioned above.
Quote:
public ObservableCollection<lossextractor.extractinfo> ExportData()
{
    BackgroundProcess = true;
    ///My code is here 
    BackgroundProcess = false;
}

You haven't shown where the ExportData is called from, but I'm assuming it's triggered by an ICommand of some sort.

The problem is, the "My code is here" part is running on the UI thread. That thread is blocked until the code has finished running. The busy indicator never gets a chance to display, because the code that changes its visibility is also running on the UI thread, and doesn't execute until your code has finished.

Try moving your code to a BackgroundWorker, so that the UI has a chance to update:
Multi-threading with the BackgroundWorker[^]
C#
private void StartExport()
{
    if (!exportBackgroundWorker.IsBusy)
    {
        BackgroundProcess = true;
        exportBackgroundWorker.RunWorkerAsync();
    }
}

private void exportBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Your code is here...
    e.Result = new ObservableCollection<lossextractor.extractinfo>(...);
}

private void exportBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    BackgroundProcess = false;
    
    if (e.Cancelled)
    {
        // Notify the user that the export was cancelled...
    }
    else if (e.Error != null)
    {
        // Display the error details to the user...
    }
    else
    {
        var exportedData = (ObservableCollection<lossextractor.extractinfo>)e.Result;
        // Do something with the data here...
    }
}
 
Share this answer
 
Comments
Ram349 19-Sep-17 4:57am    
Hi Richard,
Thanks for providing solution,it's working fine but still i am facing the "this type of collectionview does not support changes to its source collection from a thread different from the dispatcher thread" issue.could you please tel me solution,i googled that issue and i tried so many solutions but it's didn't work.
Richard Deeming 19-Sep-17 7:29am    
You get that error when you try to update an ObservableCollection from a background thread while it's bound to a UI control.

That's why the code I posted created a new collection in the DoWork handler, and only updated it in the RunWorkerCompleted handler. If you try to update an existing collection from the DoWork handler, you have to take extra steps to make it work.

If you're using .NET 4.5 or later, you can use the BindingOperations.EnableCollectionSynchronization[^] method to allow updates from a background thread.

Otherwise, you'll need to use Dispatcher.Invoke[^] or Dispatcher.BeginInvoke[^] to update the collection on the UI thread.

WPF 4.5: Observable Collection Cross-Thread Change Notification - Pete Brown's 10rem.net[^]
Ram349 20-Sep-17 1:27am    
Hi Richard,
I written code what ever your shared like that only i written.but still i am getting same issue.
Ram349 20-Sep-17 1:28am    
Alternative times its working

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900