我有一个WPF窗口,显示两个日期之间的记录列表。我用它:MVVM Light,实体框架和存储过程。
当我运行命令显示列表时,我想显示一个进度条以指示任务正在运行。查询完成后,我想隐藏进度条。 问题是进度条的可见性不能很好地工作。以下是我的代码:
//XAML
.
.
.
.
<StatusBar Grid.Row="2">
<StatusBarItem Width="300">
<TextBlock Text="{Binding SBMessage, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</StatusBarItem>
<StatusBarItem Width="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Requête en cours..." Visibility="{Binding TaskInProgress, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource booltovisibility}}" />
<ProgressBar
Visibility="{Binding TaskInProgress, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource booltovisibility}}"
Width="100"
Height="20"
IsIndeterminate="True"
VerticalAlignment="Center"
Grid.Column="1"
/>
</Grid>
</StatusBarItem>
</StatusBar>
//ViewModel
bool _taskinprogress = false;
public bool TaskInProgress
{
get { return _taskinprogress; }
set
{
_taskinprogress = value;
RaisePropertyChanged("TaskInProgress");
}
}
public RelayCommand DisplaySimulationsListCommand
{
get
{
if (_splist == null)
_splist = new RelayCommand(DisplaySimulationsListCommandExecute);
return _splist;
}
}
private void DisplaySimulationsListCommandExecute()
{
SBMessage = "Exécution...";
TaskInProgress = true;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
DoItWithStoredProcedure();
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
SBMessage = ListSimulations.Count().ToString() + " Enregistrement(s) en : " + elapsedTime;
CurrentDisplayedTab = 1;
TaskInProgress = false;
//SBMessage = "Prêt";
}
private void DoItWithStoredProcedure()
{
try
{
using (UnitOfWork cx = new UnitOfWork())
{
var ls = cx.GetSimulationsPeriode(VMPeriode.Debut, VMPeriode.Fin).AsReadOnly();
ListSimulations = new ObservableCollection<Simulation>(ls);
CVS = (ListCollectionView)CollectionViewSource.GetDefaultView(ListSimulations);
RaisePropertyChanged("CVS");
}
}
catch (Exception ex)
{
Messenger.Default.Send<ExceptionMessageRefresh>(new ExceptionMessageRefresh(ex), "DoItWithStoredProcedure");
}
}
//Converter
public class BoolToVisiblityConverter : IValueConverter
{
#region Constructors
/// <summary>
/// The default constructor
/// </summary>
public BoolToVisiblityConverter() { }
#endregion
public bool Collapse { get; set; }
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool bValue = (bool)value;
if (bValue)
return Visibility.Visible;
else
{
if (Collapse)
return Visibility.Collapsed;
else
return Visibility.Hidden;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility visibility = (Visibility)value;
if (visibility == Visibility.Visible)
return true;
else
return false;
}
#endregion
}
提前谢谢。
答案 0 :(得分:3)
接受的答案是他们过去是如何做到的(在.NET Framework 4之前),当时孩子们必须走上坡/上学。这是一个更易读的解决方案,不需要大量的代码(感谢.NET Framework 4 / 4.5)。
private void DoItWithStoredProcedure()
{
//Do your normal SP stuff here
//Instead, I mocked a synchronous method
Thread.Sleep(1000);
Console.WriteLine("Completed");
}
private void DisplaySimulationsListCommandExecute()
{
//Do stuff
Console.WriteLine("Started");
TaskInProgress = true;
Task.Run(() => DoItWithStoredProcedure())
.ContinueWith( task => { TaskInProgress = false; });
Console.WriteLine("Finished");
//Do the rest of your stuff
}
输出:
Started //Showed the ProgressBar animation
Finished //Task.Run was hit
Completed //ProgressBar became collapsed after ContinueWith is hit
证明:
正如您所看到的,您可以亲眼看到,这种被广泛接受的使用Task.Run
和ContinueWith
的方法是一个单行解决方案,可以很容易地阅读和理解。
答案 1 :(得分:0)
您需要进行异步处理,因为完成功能完成处理后,所有UI级别更改都将可用。在正常情况下,处理时间可以忽略不计,因此这种情况并不明显。
建议的更改:
// suggested changes start //
delegate void LongTaskDelegate();
private void DoItWithStoredProcedureAsync()
{
LongTaskDelegate del = new LongTaskDelegate(DoItWithStoredProcedure);
AsyncCallback callback = new AsyncCallback(LongTaskFinishedCallback);
IAsyncResult result = del.BeginInvoke(callback, null);
}
private void LongTaskFinishedCallback(IAsyncResult result)
{
TaskInProgress = false;
... some extra work
}
// suggested changes end //
private void DisplaySimulationsListCommandExecute()
{
...
TaskInProgress = true;
// call our new method declared above
DoItWithStoredProcedureAsync();
}
如果我们使用async / await模式,那么没有像通知那样的事件,我们必须用TaskInProgress = false污染我们的DoItWithStoredProcedure();这可以做但不是好的做法。我们当前的模式使用诸如通知之类的事件,并通知我们长期运行的任务完成。
答案 2 :(得分:0)
@Habib Gherairi, 为避免阻止用户界面,您可能需要添加&#39; IsAsync = True&#39;你的装订:
<ProgressBar Visibility="{Binding TaskInProgress, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource booltovisibility}, IsAsync=True}" IsIndeterminate="True" /
https://msdn.microsoft.com/en-us/library/system.windows.data.binding.isasync(v=vs.110).aspx
当绑定源属性的get访问器可能需要很长时间时,请使用IsAsync属性。一个示例是具有从Web下载的get访问器的图像属性。将IsAsync设置为true可避免在下载时阻止UI。