0

我正在开发一个 WPF 应用程序,其中用户可以通过按下 UI 上的按钮来启动一个进程。然后可能会提示用户完成该过程必须执行的一系列动作。视图负责将初始请求传递给域以启动流程。该视图还负责显示用户完成该过程必须执行的步骤。另一方面,域是对制定用户必须执行的步骤的直接响应。该域还能够检测用户何时完成了请求的步骤。

如果用户启动一个流程,并且该流程要求他们执行一些物理操作,那么我希望弹出一个框,其中包含描述他们必须做什么的消息。动作完成后,域会检测到它,并且窗口应该会自动关闭。

将请求从视图传递到域很简单。我使用 wpf ICommand 模式执行此操作。它以另一种我认为具有挑战性的方式传递信息。我知道绑定和 INotifyProperyChanged 接口,但我认为这不适合我正在尝试做的事情。

所以,这是我最初的尝试......

该接口由 View 实现并由 Domain 使用。它允许域与用户进行通信;

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);
}

这是 View 代码隐藏。其中一些代码取自网络上的教程(随后被修改)。它不起作用,但我希望它能传达我的意图。

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();
    }
}

我怎样才能使这项工作?这是我被抓住的跨线程方面。当域检测到该操作时,我未能成功地使窗口自动关闭。

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

4

1 回答 1

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);
        }
    }
于 2012-07-13T10:06:42.860 回答