按钮的DialogResult没有被重新设置?

3
在我的Windows Forms应用程序中,我有一个子窗体,由主窗体以模态方式启动。子窗体充当向导执行长时间运行任务的角色,并包含“取消”按钮。在设计器中,我将此“取消”按钮的DialogResult属性设置为DialogResult.Cancel。但是,如果用户一直拒绝按“取消”按钮直到长时间操作完成,那么“取消”按钮的文本会更改为“关闭”。如果发生这种情况,我希望按钮的DialogResultDialogResult.None
不幸的是,该设置似乎无法持久化。为了保持响应性UI,长时间运行的任务在单独的Task中运行,然后在任务完成后使用ContinueWith块进行UI更新,该块又使用Invoke来进行UI工作。代码大致如下:
Task.Factory.StartNew(() =>
{
    MyStaticClass.DoLotsOfWork(a, b, myCancellationToken);
    return MyStaticClass.TellMeAboutIt(a, c, myCancellationToken);
}, myCancellationToken)
.ContinueWith(task =>
{
    switch(task.Status)
    {
    case TaskStatus.RanToCompletion:
        Invoke((MethodInvoker)delegate
        {
            cancelButton.Text = "Close";
            cancelButton.DialogResult = DialogResult.None;
            // other UI-related stuff.
        }
    // Other cases here...
    }
});

当我运行代码时,文本被设置为“关闭”,没有问题。 DialogResult 看起来已经改变:如果我使用调试器进行步进,调试器告诉我值已经改变。然而,当窗口被关闭(使用取消/关闭按钮)时,myWindow.ShowDialog() 返回的 DialogResult 总是 DialogResult.Cancel。这是一个 bug 吗?我做错了什么吗?一个人不能在程序中动态地设置按钮的 DialogResult 吗?

你可以尝试的一件事情是,或许移除两个DialogResult,仅在Button_Click事件中处理它。接着,根据Button.Text属性设置DialogResult即可。 - dub stylee
1
我写了一个快速测试应用程序,但我无法重现那个问题。我敢打赌是其他东西设置了DialogResult。子窗体实际上是如何关闭的? - Moby Disk
你是如何关闭模态窗口的? - DrewJordan
在事件处理程序cancelButton_Click中使用this.Close() - Eric Dand
1个回答

5

导致 DialogResult 设置为 Cancel 的原因不止一个。例如,在按钮的 Click 事件处理程序中调用 Close() 是一个错误,这会关闭窗口,但由于未分配 DialogResult,Winforms 必须假定为 Cancel。隐藏窗口是触发此问题的另一种方式,当您将窗口设置为不可见时,窗口不能保持模态。必然如此,所有其他窗口都被禁用,最后剩下的一个也被隐藏了,用户再也无法返回程序。

处理对话框状态的明智方法是仅设置 DialogResult 属性。只要将其从 None 更改为其他值,Winforms 就会关闭对话框,对话框结果就是明确的。因此,请考虑删除 Click 事件处理程序并更改代码:

case TaskStatus.RanToCompletion:
    Invoke((MethodInvoker)delegate
    {
        cancelButton.Text = "Close";
        cancelButton.DialogResult = DialogResult.OK;
    }

当你说“例如,你可能会犯在按钮的Click事件处理程序中调用Close()的错误。这将关闭窗口,但由于未分配DialogResult,Winforms必须假定为Cancel”时,你的意思是什么?Close()不会导致返回所单击按钮的DialogResult吗? - Eric Dand
我需要猜测Click事件处理程序的样子,这有什么好处吗?但我敢打赌它是错误的。如果你关闭窗口但不说为什么关闭它,Winforms无法更好地猜测除了Cancel之外的其他选项。不要调用Close(),而是设置DialogResult属性。 - Hans Passant
this.Close() 不会改变 DialogResult。 - Moby Disk
啊啊啊,我现在感觉像个白痴。刚刚(重新)阅读了MSDN文档中关于DialogResult的部分。是的,Hans,我确实会显式地调用Close()方法。我不知道设置了DialogResult属性的按钮会自动关闭窗口!谢谢。 - Eric Dand
这正是我想说的。说得好,汉斯。 - DrewJordan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接