如何弹出依赖后台任务逻辑的消息?

时间:2014-08-01 03:40:51

标签: c# wpf multithreading mvvm task

现在我有以下内容:

private void DoSomethingAsync() {

    ProgressBarVisibility = Visibility.Visible;
    Task.Factory.StartNew(() => { PerformCDDetection(); }).ContinueWith(t => { ProgressBarVisibility = Visibility.Collapsed; });
}



 public ICommand ImportFilePathCommand
{
    get
    {
        return new RelayCommand(() => { DoSomethingAsync(); });
    }

}
  private void PerformCDDetection()
{
    //Gets all the drives 
    DriveInfo[] allDrives = DriveInfo.GetDrives();

    //checks if any CD-Rom exists in the drives
    var cdRomExists = allDrives.Any(x => x.DriveType == DriveType.CDRom);

    // Get all the cd roms
    var cdRoms = allDrives.Where(x => x.DriveType == DriveType.CDRom && allDrives.Any(y => y.IsReady));

    if (cdRomExists.Equals(true))
    {
        // Loop through the cd roms collection
        foreach(var cdRom in cdRoms)
        {
            Console.WriteLine("Drive {0}", cdRom.Name);
            Console.WriteLine("  File type: {0}", cdRom.DriveType);

            if (cdRom.IsReady == true)
            {
                if (cdRom.DriveType == DriveType.CDRom)
                {
                    DirectoryInfo di = new DirectoryInfo(cdRom.RootDirectory.Name);

                    var file = di.GetFiles("*.xml", SearchOption.AllDirectories).FirstOrDefault();

                    if (file == null)
                    {
                        Console.WriteLine("failed to find file"); 
                    }
                    else
                    {
                        foreach (FileInfo info in di.GetFiles("*.xml", SearchOption.AllDirectories))
                        {
                            Debug.Print(info.FullName);
                            break;      // only looking for the first one
                        }
                        break;
                    }
                }
            }
            else if (cdRom.IsReady == false)
            {
                Console.WriteLine("Cd-ROM is not ready");
                break;
            }

        }
    }
    else
    {
        Console.WriteLine("CD ROM is not detected");

    }

} 

Console.WriteLine语句应该是dialogWindows / Message Box,弹出警告用户列出的条件。

我删除了消息并用Console.WriteLine语句替换它,因为我无法在后台任务上运行messagebox.show()(它应该是UI线程的一部分而不是后台)。

我想知道因为根据在后台执行的逻辑显示消息,我该如何显示消息框?

在以下示例中,如何在UI线程和后台线程之间来回切换?

编辑:这是我想在UI线程上运行的一段代码:

  errorWindow.Message = LanguageResources.Resource.File_Not_Found;
  dialogService.ShowDialog(LanguageResources.Resource.Error, errorWindow);
  break;

如果我这样做:

Dispatcher.BeginInvoke(() =>
{
    errorWindow.Message = LanguageResources.Resource.File_Not_Found;
    dialogService.ShowDialog(LanguageResources.Resource.Error, errorWindow);
    break;
}
);

我收到以下错误消息:

Control cannot leave the body of an anonymous method or lambda expression (for break;)

Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type    

我使用break来摆脱循环,我应该绕过我的逻辑来避免使用break还是有办法让我仍然可以使用break?

2 个答案:

答案 0 :(得分:2)

您可以创建可从应用程序的任何部分访问或调用的可重用MessageService。

这样的事情:

注意:此代码假定在UI线程上创建了MessageService实例。如果您将此实例注入BootStrapper内的容器,通常就是这种情况。否则,即使您从任何.xaml.cs代码中实例化,也可以工作。

        /// <summary>
        /// Could be injected to your UnityContainer as singleton and then accessed by using Container.Resolve
        /// </summary>

    public interface IMessageService
    {
        void ShowDialog(string message, MessageBoxButton messageBoxButton);
    }

    public class MessageService : IMessageService
    {
        private readonly Dispatcher _dispatcher;

        public MessageService()
        {
          if(Application.Current!=null){
             _dispatcher = Application.Current.Dispatcher;
          }
          else{
            _dispatcher = Dispatcher.CurrentDispatcher;
          }
        }

        public void ShowDialog(string message, MessageBoxButton messageBoxButton)
        {
            if (_dispatcher.CheckAccess())
            {
                Show(message, messageBoxButton);
            }
            else
            {
                _dispatcher.Invoke(new Action(() => Show(message, messageBoxButton)));
            }
        }

        private static void Show(string message, MessageBoxButton messageBoxButton)
        {
            MessageBox.Show(Application.Current.MainWindow, message, "TITLE", messageBoxButton);
        }
    }

编辑:如果不使用任何统一容器,您只需从代码中实例化MessageService即可。喜欢内部&#34; DoSomethingAsync&#34;在你的情况下。

答案 1 :(得分:1)

您应该查看Dispatcher.Invoke和Dispatcher.BeginInvoke方法。

MSDN链接:http://msdn.microsoft.com/en-us/library/System.Windows.Threading.Dispatcher_methods%28v=vs.110%29.aspx

您可以执行以下操作:

Dispatcher.BeginInvoke((Action)(() => MessageBox.Show("some message to display")));

  

控件不能离开匿名方法或lambda的主体   表达式(用于休息;)

中断需要在Dispatcher调用之外。 你可以这样做:

Dispatcher.BeginInvoke(...);
break;

其他人可以看到:

正如聊天中所讨论的,您需要从UI线程中获取调度程序,然后将其传递给您的任务。

示例:

private void DoSomethingAsync() {
    /* here we are on the UI thread */
    Dispatcher dispatcher = (Application.Current!=null) ?
         Application.Current.Dispatcher :
         Dispatcher.CurrentDispatcher;

    ProgressBarVisibility = Visibility.Visible;
    Task.Factory.StartNew(() => { 
             /* here we are on the background thread */ 
             PerformCDDetection(dispatcher); 
         }).ContinueWith(t => { ProgressBarVisibility = Visibility.Collapsed; });
}

你需要对Manish的课程做同样的事情:

private void DoSomethingAsync() {
    MessageService messageService = new MessageService();

    ProgressBarVisibility = Visibility.Visible;
    Task.Factory.StartNew(() => { PerformCDDetection(messageService); }).ContinueWith(t => { ProgressBarVisibility = Visibility.Collapsed; });
}