WPF MVVM中没有显示忙指示符? [英] Busy indicator is not displaying in WPF MVVM?

查看:75
本文介绍了WPF MVVM中没有显示忙指示符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我正在尝试在运行长任务时创建一个

忙碌指标

,但

忙碌指标

没有显示

i am使用以下代码



XAML代码是:

 <   UserControl     x:Class   =  ELT_Data_Extractor.View .DataBaseBrowser  

< span class =code-attribute> xmlns = http://schemas.microsoft.com/winfx/2006/xaml/presentation

xmlns:x = http://schemas.microsoft.com/winfx/2006/xaml

< span class =code-attribute> 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:可忽略 = d

d:DesignHeight = 600 d:DesignWidth = 576 >
< UserControl.Resources >
< viewmodel:ExtractInfoVM x:Key = vm > < / viewmodel:ExtractInfoVM >

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

< 网格 高度 = 540 >
< Grid.RowDefinitions >
< RowDefinition
高度 = 400 / >
< RowDefinition 高度 = 5 / >
< RowDefinition 高度 = 102 / >
< RowDefinition 高度 = 53 * / >




< / Grid.RowDefinitions >
< StackPanel DataContext = {Binding Source = {StaticResource vm}} >
< 网格 高度 = 400 >
< Grid.RowDefinitions >
< RowDefinition 高度 = 33 * / >
< RowDefinition 高度 = 33 * / >
< RowDefinition 高度 = 33 * / >
< RowDefinition 高度 = 89 * / >
< < span class =code-leadattribute> RowDefinition 高度 = 41 * / >
< RowDefinition 高度 = 41 * / >
< RowDefinition 高度 = 41 * / >
< RowDefinition 高度 = 18 * / >
< RowDefinition 高度 = 35 * / >
< RowDefinition 高度 = 35 * / >

< / Grid.RowDefinitions >
< Grid.ColumnDefinitions >
< ColumnDefinition 宽度 = 11 / >
< ColumnDefinition 宽度 = 94 / >
< ColumnDefinition 宽度 = 178 * / >
< ColumnDefinition 宽度 = 261 * / >
< < span class =code-leadattribute> ColumnDefinition
宽度 = 10 * / >

< / Grid.ColumnDefinitions >



< 标签 内容 = 供应商: Grid.Column = 1 高度 = 25 Horizo​​ntalAlignment = 拉伸 名称 = lblVendor VerticalAlignment = 中心 Grid.ColumnSpan = 3 保证金 = 0,4 / >
< ComboBox ItemsSource = {Binding VendorList}

< span class =code-attribute> SelectedValue = {Binding SelectedVendor}

Grid.Column = 2 高度 < span class =code-keyword> = 23 Horizo​​ntalAlignment = 拉伸 名称 = cboVendor VerticalAlignment = 中心 Grid.ColumnSpan = 2 < span class =code-attribute> 保证金 = 0,5 >

< / ComboBox >

< 标签 内容 = 服务器: < span class =code-attribute> Grid.Column = 1 高度 = 25 Horizo​​ntalAlignment = 拉伸 名称 = lblServer VerticalAlignment = 中心 Grid.ColumnSpan = 3 保证金 = 0,1,0,7 Grid.Row = 1 / >
< ComboBox Grid.Column = 2 ItemsSource = {Binding Servers}

< span class =code-attribute> SelectedValue = {Binding SelectedServer}

高度 = 23 Horizo​​ntalAlignment = 拉伸 名称 = cboServer VerticalAlignment = 中心 网格.ColumnSpan = 2 保证金 = 0,3,0,7 Grid.Row = 1 / >

< 标签 内容 = 数据库: Grid.Colu mn = 1 Grid.Row = 1 高度 = 25 Horizo​​ntalAlignment = 拉伸 名称 = lblDataBase VerticalAlignment = 中心 Grid.ColumnSpan = 3 保证金 = 0,32,0,9 Grid.RowSpan = 2 < span class =code-attribute> / >
< ComboBox Grid.Column = 2 ItemsSource = {绑定数据库}

< span class=\"code-attribute\"> 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}\"

< span class=\"code-attribute\"> 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\"< span class=\"code-attribute\"> 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}}}\"

\t\t\t\t\t\tCommandParameter=\"{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

private bool _backgroundprocess; 

public bool BackgroundProcess
{
\tget { return _backgroundprocess; }
\tset
\t{
\t\tif (value != _backgroundprocess)
\t\t{
\t\t\t_backgroundprocess = value;
\t\t\tOnPropertyChanged(\"BackgroundProcess\");
\t\t}
\t}
}

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

\tbackgroundprocess = false;
}





What I have tried:



i was tried to implement in the Mainwindow its working fine

解决方案

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:

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



and here:

< pre lang=\"xml\"><StackPanel DataContext=\"{Binding Source={StaticResource vm}}\">



and here:

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

<UserControl.Resources> 
\t<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:

using GalaSoft.MvvmLight; 
使用 GalaSoft.MvvmLight.CommandWpf;
using GalaSoft.MvvmLight.Threading;
使用 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:

using GalaSoft.MvvmLight.Threading; 
使用 System.Windows;

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



3. The MainWindow XAML:

<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>
&l t;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.


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[^]

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


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 :

<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

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

解决方案

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:

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


and here:

<StackPanel DataContext="{Binding Source={StaticResource vm}}">


and here:

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

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

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:

using GalaSoft.MvvmLight.Threading;
using System.Windows;

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


3. The MainWindow XAML:

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


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[^]

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


这篇关于WPF MVVM中没有显示忙指示符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆