2012-07-13 55 views
0

我正在WPF应用程序中,用户可以通过在UI上按下按钮来启动进程。用户可能会被提示一系列必须执行的操作来完成该过程。该视图负责传递初始请求以启动到域的过程。该视图还负责显示用户必须执行的完成该过程的步骤。另一方面,该领域对于解决用户必须执行的步骤是正确的响应。该域还能够检测用户何时完成了请求的步骤。从域传递请求到查看

如果用户启动一个进程,并且该进程要求他们执行一些物理操作,那么我想要一个盒子弹出一条消息来描述他们必须执行的操作。当动作完成后,它会被域检测到,并且窗口应该自动关闭。

将视图向下传递到域的请求很简单。我使用wpf ICommand模式执行此操作。它将信息传递给另一种我发现具有挑战性的方式。我知道绑定和INotifyProperyChanged接口,但我不觉得这是适合我所要做的。

所以,这里是我的初步尝试...

该接口由视图实现,消耗的域。它允许域与用户通信;

public interface IUserRequestMedium 
{ 
    /// <summary> 
    /// Ask the user to perform an action. User does 
    /// not need to provide any feedback via the user 
    /// interface, since it is possible for the 
    /// application to detect when the action has been 
    /// carried out by the user. The dialog will be closed 
    /// when either the requested action has been detected, 
    /// or the user aborts. 
    /// </summary> 
    /// <param name="message"> 
    /// Request to be displayed to the user. 
    /// </param> 
    /// <param name="userAbortCallback"> 
    /// Callback invoked by the view when the user cancels 
    /// the request. 
    /// </param> 
    /// <param name="actionDetectedCallback"> 
    /// Callback invoked by the domain to confirm the 
    /// that the requested action has been completed. 
    /// </param> 
    void AskUserToPerformDetectableAction(
     string message, Action userAbortCallback, 
     out Action actionDetectedCallback); 
} 

这是查看代码隐藏。这些代码中的一部分来自Web上的教程(并随后发生了破坏)。这不起作用,但我希望它能传达我的意图。

public partial class MainWindow : Window, IUserRequestMedium 
{ 
    // Constructor and other stuff... 

    public void AskUserToPerformDetectableAction(
     string message, Action userAbortCallback, 
     out Action actionDetectedCallback) 
    { 
     Action closeWindow; 
     NewWindowThread(
      () => new ActionRequestBox(message, userAbortCallback), 
      out closeWindow); 

     actionDetectedCallback = closeWindow; 
} 

    private Window newWindow; 

    private void NewWindowThread(
     Func<Window> construction, 
     out Action closeWindow) 
    { 
     var thread = new Thread(() => 
     { 
      newWindow = construction(); 
      newWindow.Show(); 
      newWindow.Closed += (sender, e) => newWindow.Dispatcher.InvokeShutdown(); 
      System.Windows.Threading.Dispatcher.Run(); 
     }); 
     thread.SetApartmentState(ApartmentState.STA); 
     thread.Start(); 

     Window rememberedWindow = newWindow; 
     closeWindow =() => 
     { 
      if (rememberedWindow != null) 
       rememberedWindow.Dispatcher.Invoke(
        System.Windows.Threading.DispatcherPriority.Normal, 
        new Action(Close)); 
     }; 
    } 
} 

下面是来自域的使用示例;

public class SomeDomainClass 
{ 
    IUserRequestMedium userRequestMedium; // assume this has been assigned in constructor 

    private Action notifyUserOfActionDetected; 

    public void PerformSomeProcess() 
    { 
     bool processCannotBeCompletedWithoutPowerCycle = ...; // some logic 
     if (processCannotBeCompletedWithoutPowerCycle) 
     { 
      userRequestMedium.AskUserToPerformDetectableAction(
       "Please cycle the power on the external device", 
       CancelProcess, 
       out notifyUserOfActionDetected); 
     } 
    } 

    public void CancelProcess() 
    { 
     // User doesn't want to perform the required action 
     // so process must be aborted... 
    } 

    private void OnPowerCycleDetected() 
    { 
     notifyUserOfActionDetected(); 
    } 
} 

我该如何做这项工作?这是跨线程方面,我陷入了。当域被检测到动作时,我没有成功地让窗口自动关闭。

或者,向后退一步,是否有更好的方法来解决这个问题?

回答

0

在了解了一些有关Dispatcher.Invoke的知识之后,这就是我最终得到的结果。到目前为止,它似乎工作得很好。

private Window activeRequestBox; 

    // invoked on domain thread 
    public void AskUserToPerformDetectableAction(
     string message, Action userAbortCallback, 
     out Action actionDetectedCallback) 
    { 
     OpenDetectableActionRequestBox(message, userAbortCallback); 
     actionDetectedCallback = CloseRequestBox; 
    } 

    private void OpenDetectableActionRequestBox(
     string message, Action userAbortCallback) 
    { 
     Action openWindow = 
      () => 
      { 
       activeRequestBox = new DetectableActionRequestBox(
        message, userAbortCallback); 
       activeRequestBox.Closed += RequestBoxClosedHandler; 
       activeRequestBox.Show(); 
      }; 
     this.Dispatcher.Invoke(openWindow);    
    } 


    // invoked on request box thread 
    private void RequestBoxClosedHandler(object sender, EventArgs e) 
    { 
     activeRequestBox = null; 
    } 

    // invoked on domain thread 
    private void CloseRequestBox() 
    { 
     if (activeRequestBox != null) 
     { 
      Action closeWindow = 
       () => activeRequestBox.Close(); 
      this.Dispatcher.Invoke(closeWindow); 
     } 
    }