I'm writing an application in WPF using Caliburn Micro. Following some tutorials on their website I wanted to implement a BusyIndicator control from the Xceed.Wpf.Toolkit. I'm using coroutines and return IEnumerable from my method to do 3 things: show the busy indicator, switch screens, hide the busy indicator. Seems simple enough, but whats happening is, the BusyIndicator never shows up. I think there's something I don't understand about the way WPF renders its controls. Here's some code.
我正在使用Caliburn Micro在WPF中编写应用程序。在他们网站上的一些教程之后,我想从Xceed.Wpf.Toolkit实现一个BusyIndicator控件。我正在使用协同程序并从我的方法返回IEnumerable来做3件事:显示忙碌指示器,切换屏幕,隐藏忙碌指示器。看起来很简单,但最新发生的是,BusyIndicator永远不会出现。我认为有一些我不了解WPF呈现其控件的方式。这是一些代码。
This is my Loader class for displaying my BusyIndicator control on the ShellView.xaml
这是我的Loader类,用于在ShellView.xaml上显示我的BusyIndicator控件
public class Loader : IResult
{
private readonly String _message;
private readonly bool _hide;
private readonly IShell _shell;
public Loader(IShell shell, String message)
{
_message = message;
_shell = shell;
}
public Loader(IShell shell, bool hide)
{
_hide = hide;
_shell = shell;
}
public void Execute(CoroutineExecutionContext context)
{
var view = _shell.View as ShellView;
if (view == null)
return;
if (_hide)
{
view.BusyIndicator.IsBusy = false;
}
else
{
view.BusyIndicator.BusyContent = _message;
view.BusyIndicator.IsBusy = true;
// I WOULD ASSUME THIS WOULD IMMEDIATELY UPDATE THE BusyIndicator CONTROL TO SHOW BUT IT DOESNT
}
Completed(this, new ResultCompletionEventArgs());
}
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
public static IResult Show(String message = null)
{
return new Loader(IoC.Get<IShell>(), message);
}
public static IResult Hide()
{
return new Loader(IoC.Get<IShell>(), true);
}
}
This is my ShowScreen class that navigates to the next screen by getting the IShell and calling ActivateItem. Nothing fancy here.
这是我的ShowScreen类,它通过获取IShell并调用ActivateItem导航到下一个屏幕。这里没什么好看的。
public class ShowScreen : IResult
{
private readonly Type _screenType;
public ShowScreen(Type screenType)
{
_screenType = screenType;
}
public void Execute(CoroutineExecutionContext context)
{
var screen = IoC.GetInstance(_screenType, null);
shell.ActivateItem(screen);
Completed(this, new ResultCompletionEventArgs());
}
public event EventHandler<ResultCompletionEventArgs> Completed;
public static ShowScreen Of<T>()
{
return new ShowScreen(typeof(T));
}
}
Both of these on their own work with no problems, its when I chain them together in a coroutine like this is when it doesnt work the way I'd expect:
这两个都在他们自己的工作上没有任何问题,当我把它们连接在一起像这样的协同时,它就像它没有按照我期望的方式工作:
public class HomeViewModel : Screen
{
public IEnumerable<IResult> OpenFirstPage()
{
yield return Loader.Show("Please Wait");
yield return ShowScreen.Of<FirstPageViewModel>();
yield return Loader.Hide();
}
}
I almost feel like I need to tell WPF to explicitly show my BusyIndicator somehow. Like it doesn't instantly show the BusyIndicator when I tell it to. When I take out the last Loader.Hide() command, it navigates to the next screen THEN shoes the BusyIndicator. This is driving me insane.
我几乎觉得我需要告诉WPF以某种方式明确地显示我的BusyIndicator。就像我告诉它时不会立即显示BusyIndicator。当我取出最后一个Loader.Hide()命令时,它导航到下一个屏幕,然后穿上BusyIndicator。这让我疯了。
1 个解决方案
#1
1
After messing with this stupid thing all night I've finally found a solution. In my ShowScreen class I needed to wrap the showing of the screen in a Task.Factory.StartNew() like this
整晚搞砸了这个蠢事之后我终于找到了解决办法。在我的ShowScreen类中,我需要在这样的Task.Factory.StartNew()中显示屏幕的显示
public void Execute(CoroutineExecutionContext context)
{
Task.Factory.StartNew(() =>
{
object screen = null;
var shell = IoC.Get<IShell>();
if (_viewModel != null)
{
screen = _viewModel;
}
else
{
screen = !String.IsNullOrEmpty(_name)
? IoC.Get<object>(_name)
: IoC.GetInstance(_screenType, null);
}
shell.ActivateItem(screen);
Completed(this, new ResultCompletionEventArgs());
});
}
Now everything executes in the order I want it to execute. Thanks @pushpraj for the ideas.
现在一切按我希望它执行的顺序执行。感谢@pushpraj的想法。
#1
1
After messing with this stupid thing all night I've finally found a solution. In my ShowScreen class I needed to wrap the showing of the screen in a Task.Factory.StartNew() like this
整晚搞砸了这个蠢事之后我终于找到了解决办法。在我的ShowScreen类中,我需要在这样的Task.Factory.StartNew()中显示屏幕的显示
public void Execute(CoroutineExecutionContext context)
{
Task.Factory.StartNew(() =>
{
object screen = null;
var shell = IoC.Get<IShell>();
if (_viewModel != null)
{
screen = _viewModel;
}
else
{
screen = !String.IsNullOrEmpty(_name)
? IoC.Get<object>(_name)
: IoC.GetInstance(_screenType, null);
}
shell.ActivateItem(screen);
Completed(this, new ResultCompletionEventArgs());
});
}
Now everything executes in the order I want it to execute. Thanks @pushpraj for the ideas.
现在一切按我希望它执行的顺序执行。感谢@pushpraj的想法。