views:

1652

answers:

5

Can anyone think of a good explanation for the fact that result of a dialog is a nullable bool in WPF? This has always baffled me. In WinForms it was an enum type and that made a lot more sense to me.

+1  A: 

According to the MSDN documentation:

DialogResult is null when the dialog box is shown but neither accepted nor canceled.

But I'm not sure how that could happen unless you're dealing with multiple threads accessing the dialog.

The documentation says is false when one of the following things happen:

  • PressesALT+F4.
  • Clicks the Close button.
  • Selects Close from the System menu.
Max Schmeling
I think it happens when the user clicks the Close button on the top-right of the window.
Samuel Jack
not according to the documentation i linked to... i'll edit with more detail
Max Schmeling
@Max, if you call `Show` then the call returns to you (ie. it's a non-blocking call), so you're free to interrogate the `DialogResult` value straight away. It's only if you call `ShowDialog` that the call blocks until the dialog is dismissed. However in the latter case, you're still free to interrogate the object from another thread, as you point out.
Drew Noakes
+9  A: 

The DialogResult property is defined on the Window class. Not all Windows are dialogs. Therefore, the property isn't relevant to all windows. A Window that has been shown via Show() rather than ShowDialog() will (presumably, unless you set it for some reason) have DialogResult = null.

Here's a simple example to demonstrate:

Window1.xaml:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
     <Button Name="b1">Show</Button>
     <Button Name="b2">ShowDialog</Button>
    </StackPanel>
</Window>

Window1.xaml.cs:

using System.Windows;

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
     public Window1()
     {
      InitializeComponent();
      b1.Click += new RoutedEventHandler(b1_Click);
      b2.Click += new RoutedEventHandler(b2_Click);
     }

     void b1_Click(object sender, RoutedEventArgs e)
     {
      var w = new Window();
      w.Closed += delegate
      {
       MessageBox.Show("" + w.DialogResult);
      };

      w.Show();
     }

     void b2_Click(object sender, RoutedEventArgs e)
     {
      var w = new Window();
      w.ShowDialog();
      MessageBox.Show("" + w.DialogResult);
     }
    }
}

When you close the windows, you'll notice that the dialog has a DialogResult of false, whilst the non-dialog has a null DialogResult.

HTH, Kent

Kent Boogaart
While this is true and probably pertinent there was already a 'None' value in the DialogResult enum which would have fulfilled the purpose of null in this example quite comfortably. So I doubt a desire to have a null value was reason enough to move from the established model.
Martin Harris
To me, null means completely irrelevant whereas None suggests it's relevant but not yet set. *shrugs* Semantics.
Kent Boogaart
Funnily enough I would read it the other way. Null is an unset value and None means that there isn't and won't ever be a DialogResult. Maybe that type of confusion was reason enough to change the model.
Martin Harris
"The DialogResult property is defined on the Window class. Not all Windows are dialogs." These two sentences seem true, and hilarious at the same time.
PeterAllenWebb
A: 

ShowDialog will always return true or false. DialogResult will only take the null state when the dialog is open. Transitioning from null to true or false will close the dialog and make the original call to ShowDialog return.

pjbelf
+3  A: 

In my opinion this was done because in most cases you don't need the generalized specialized options like Retry or Ignore.

If you need more than OK/Cancel, you are supposed to use some kind of task dialog, e.g. with written-out answers. That way, you're not limited to the few enum values someone thought of some decades ago, and the DialogResult is just positive/negative for basic use and you can implement your own property that is specific to your advanced needs. Therefore only true/false is needed, and null indicating that the window has not been closed yet (no value has been assigned to the property yet).

If you have a dialog that is more than just a question the user should answer (e.g. an entry form), you're typically better off with OK/Cancel, so you don't need more values.

OregonGhost
Then why Nullable(Of Boolean), why not just Boolean, or ThreeState?
Shimmy
bool? is, in my opinion, easier to handle than yaetr (yet another enum to remember). And the null value may be useful for bindings as an unassigned value, in contrast to definite true/false values. Of course, *I don't know* why it's like that, just guessing :)
OregonGhost
A: 

IMO this is because DialogResult isn't always used. You see, you can only set DialogResult if the window is called by its ShowDialog() method, if you call it with its Show() method, and try to set DialogResult to anything, it'll throw an InvalidOperationException. So I think that is the reason it's nullable, in case you call the window with the Show() method, it'll be null, if you call it using ShowDialog(), it's up to you.

Carlo
Hmm this answer was already told by Kent Boogaart, sorry for reposting!
Carlo