在实现用于窗体关闭的 WPF MVVM 模式时获取"DialogResult can be set only after Window is created and shown as dialog"



我正在尝试实现WPF表单关闭的MVVM模式,这在本博客中也有解释,我正在获得系统。当我试图在关闭按钮命令上设置对话框结果时,InvalidOperationException错误信息"只有在创建窗口并显示为对话框后才能设置对话框结果":

DialogResult = true;
这是我的ViewModel:
class MainWindowViewModel:INotifyPropertyChanged
{
    private bool? dialogResult;
    public bool? DialogResult
    {
        get { return dialogResult; }
        set
        {
            if (value != this.dialogResult)
            {
                this.dialogResult = value;
                OnPropertyChanged("DialogResult");
            }
        }
    }
    public string Text
    {
        get { return "Hello!"; }
    }
    void CloseCommandExecute()
    {
        this.DialogResult = true;
    } 

<Window x:Class="WpfApplication.Mvvm.Windowclosing.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication.Mvvm.Windowclosing"
        local:DialogCloser.DialogResult="{Binding DialogResult}"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding Text}" Grid.Row="0"/>
        <Button Grid.Row="1" Command="{Binding CloseCommand}">Close Me</Button>
    </Grid>
</Window>

我在这里做错了什么?

设置对话框结果仅在使用ShowDialog()打开表单时有效。当您尝试在使用Show()打开的表单上设置对话框结果时,会得到此错误。

我在创建一个通过ShowDialog()调用的窗口时遇到了这个问题。在窗口中,我有一个Ok_Clicked,它包含了一堆语句。为了"保证"对话框返回false,如果有任何错误,我首先将DialogResult初始化为false。如果一切都是正确的,那么我将DialogResult设置为true并关闭窗口。我一直得到相同的异常。

我了解到,如果DialogResult未设置为true, ShowDialog将始终返回false。当我在Ok_Clicked的开头删除DialogResult = false时,我不再得到异常。

我想到了另一个可能对别人有帮助的答案。在设置对话sult之前,我最终在窗口上调用Close()。请确保不要这样做,否则将导致此错误。

对于使用ShowDialog的用户,您可以从按钮中删除属性:

IsCancel = true和 IsDefault = true

我知道这个线程已经很老了,但今天我遇到了同样的问题。我做错的是,我用ShowDialog()打开了一个新窗口,而不是用Close()关闭了新窗口,并试图将dialgresult设置为True。

但是它已经足够了,如果你只设置对话sult为True,之后窗口将自动关闭,没有必要调用Close()方法。

由于绑定,您试图过早设置Window.DialogResult。假设您的DialogCloser.DialogResult(您没有向我们展示)实现也将DialogResult设置在Window上。尝试将绑定模式更改为OneWayToSource,以便更改仅传播到您的VM,而不是其他方式:

local:DialogCloser.DialogResult="{Binding DialogResult, Mode=OneWayToSource}"

或者也许这只是一个问题,改变你的行为,只有设置Window.DialogResult,如果Window已经显示为一个对话框。没有看到一切很难说。

我得到这个错误,并通过在单击事件处理程序中的任何其他代码之前设置dialgresult来解决它。当它结束时,就在Close之前,我就会得到错误。但在一开始,它是有效的。

我有

IsDefault="True"

上定义多个按钮。

我遇到了同样的问题,使用ShowDialog()并在调用close之前设置结果。

我所做的就是在设置结果之前隐藏对话框。所以,当设置对话sult的可见性必须设置为可见,隐藏和折叠都会给你一个误导性的错误,"对话sult只能在窗口创建并显示为对话框后设置。"

对于我来说,像Jarvis一样,这个错误是由于在调用Close()之后为通过ShowDialog()显示的窗口设置了dialgresult而引起的。

在我的情况下,我认为这是因为我正在将代码从WinForms移植到WPF。这个顺序在WinForms中工作得很好,但是WPF不喜欢它。

我尝试了其他的修复,比如从我的按钮中删除isDefault和isCancel属性,但这些都没有效果。

我的方法是将对话框作为Close Me按钮的命令参数传递。这种方法是在Galasoft MVVM Light Toolkit的帮助下完成的。

首先,您应该通过添加这段代码 来定义您的窗口名称
x:Name="mainWindow"

然后设置mainWindow"作为Close Me按钮命令的命令参数。

<Window x:Class="WpfApplication.Mvvm.Windowclosing.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication.Mvvm.Windowclosing"
    x:Name="mainWindow"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <local:MainWindowViewModel />
</Window.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <TextBlock Text="{Binding Text}" Grid.Row="0"/>
    <Button Grid.Row="1" 
            Command="{Binding CloseCommand}"
            CommandParameter="{Binding ElementName=mainWindow}">Close Me</Button>
</Grid>

在视图模型中,更新CloseCommandExecute()以包含Window作为其参数,并根据该参数设置dialgresult的值

void CloseCommandExecute(Window window)
{
    window.DialogResult = true;
}

命令属性如下所示:

private ICommand _btnCloseMeCmd;
public ICommand CloseMeCmd
    {
        get
        {
            if (_btnCloseMeCmd== null)
            {
                _btnCloseMeCmd= new RelayCommand<Window>(CloseCommandExecute, null);
            }
            return _btnCloseMeCmd;
        }
    }

不要忘记在视图模型中添加using GalaSoft.MvvmLight.Command;

最新更新