0

Imagine you have a property and a private field:

private MessageBoxResult doNotUseMe_Result;

public MessageBoxResult MyResult
{
    get { return doNotUseMe_Result; }
    set
    {
        doNotUseMe_Result = value;
    }
}

MessageBoxResult is an enum which is used to get the result of a MessageBox (WPF). Nevertheless I am getting problems when passing MyResult to methods, because it automatically uses the value type of the enum and changed results are getting collected by the GC, because it is now a totally new variable which is specified inside the scope of my method (TaskBasedShow)...

My current setup:

public delegate void OnResult(MessageBoxResult res);

private MessageBoxResult doNotUseMe_Result;

public MainWindow()
{
    InitializeComponent();

    OnRes += MessageBox_OnRes;

    TaskBasedShow("My message", "My caption", MessageBoxButton.YesNo, MessageBoxImage.Question, MyResult);
}

public MessageBoxResult MyResult
{
    get { return doNotUseMe_Result; }
    set
    {
        doNotUseMe_Result = value;
        OnRes?.Invoke(value);
    }
}


public void TaskBasedShow(string message, string caption, MessageBoxButton buttons,
        MessageBoxImage image, MessageBoxResult resultprop)
{
    Task.Factory.StartNew(() => { resultprop = MessageBox.Show(message, caption, buttons, image); });
}

/// <summary>
///     Is getting triggered after the user pressed a button.
/// </summary>
/// <param name="res">The pressed button.</param>
private void MessageBox_OnRes(MessageBoxResult res)
{
    MessageBox.Show(res.ToString());
}


public event OnResult OnRes;

I do have read the following documentations:

but it seems like enum does not provide a Set(value) method.


The problem:

When setting the variable of a property of an enum (inside a mothod), the setter does not get triggered and therefore my custom events.

What it should do:

It should trigger OnRes when setting the property because my setter is getting triggered and therefore my subscribers of the OnResult event. Working example:

public MainWindow()
{
    InitializeComponent();

    OnRes += MessageBox_OnRes;

    MyResult = MessageBoxResult.Cancel;
}

It will than open another messagebox displaying "Cancel".

Note:

One solution would be using the property inside TaskBasedShow:

Task.Factory.StartNew(() => { MyResult = MessageBox.Show(message, caption, buttons, image); });

because it now uses the reference type and not the passed value type.

TheRealVira
  • 1,444
  • 4
  • 16
  • 28
  • 3
    Enum is a value type. It has nothing to do about references. Or I just don't get your question. – Yeldar Kurmangaliyev Nov 13 '16 at 09:57
  • @YeldarKurmangaliyev http://stackoverflow.com/questions/14561338/enum-is-reference-type-or-value-type – TheRealVira Nov 13 '16 at 09:58
  • I have trouble understanding your problem. Can you provide a minimal example (you'll probably have to hand-code a minimal window to avoid the standard clutter), plus the expected result vs. the result you unexpectedly see? – Peter - Reinstate Monica Nov 13 '16 at 09:59
  • What's you're actual problem? Do you get an error? where? – Nick.Mc Nov 13 '16 at 09:59
  • This article tells that **specific enum** is a value type. I.e., when you make `MyResult = MessageBoxResult.Something`, it works with value, not reference. And when you pass it to a method `OnRes?.Invoke(value);`, it passes its value. @TheRealVira – Yeldar Kurmangaliyev Nov 13 '16 at 10:00
  • @YeldarKurmangaliyev So a wrapper class would do the trick right? – TheRealVira Nov 13 '16 at 10:01
  • 1
    @TheRealVira I haven't understood why you would need it to behave as a reference. In general, it sounds like a hack, not a solution. Enums are designed to be value types, just think of them as of ints, and design your application to follow this idea. It is better to find another architectural solution than making enum behave as a reference by creating artificial wrapper class. – Yeldar Kurmangaliyev Nov 13 '16 at 10:03
  • Specific questions: (1) "when setting the value..." : Where? (2) ... "...it automatically loses the reference to the property...": Which reference? How do you observe that? (3) "...and changed results are getting collected by the GC...: How do you know? – Peter - Reinstate Monica Nov 13 '16 at 10:10
  • @PeterA.Schneider (1) inside my `TaskBasedShow` method; (2) to my property, because my setter does not get triggered; (3) where else should they go? – TheRealVira Nov 13 '16 at 10:19

1 Answers1

3

You should use a callback to get the result value back

public async void TaskBasedShow( 
    string message, 
    string caption, 
    MessageBoxButton buttons,
    MessageBoxImage image, 
    Action<MessageBoxResult> resultCallback)
{
    var result = await Task.Run(() => MessageBox.Show(message, caption, buttons, image ) );
    resultCallback( result );
}

and call it like

TaskBasedShow(
    "My message", 
    "My caption", 
    MessageBoxButton.YesNo, 
    MessageBoxImage.Question, 
    r => MyResult = r );
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
  • Well the callback action is called after the MessageBox and inside this callback you set the property value which will raise the event ... – Sir Rufo Nov 13 '16 at 10:49
  • I was a bit dense when I tried to understand what you (the OP) were trying to do. Yes, this is the right solution; what's passed in your original code is *the result of a call to `MyResult.get()`!* Remember, a variable can stand in for a literal, and a property can stand in for a variable. What you want to pass is the *function* (in the shape of a delegate, like in this example), not the *result of a call to a function* (like in your code). (Properties are functions.)--- Oh, and the gc has nothing to do with any of it. – Peter - Reinstate Monica Nov 13 '16 at 11:17
  • @PeterA.Schneider it is correct that the GC has nothing to do with the question/answer, but I wanted to clarify that the passed enum value is just garbage when only used to be set again inside the scop of the `TaskBasedShow` method! – TheRealVira Nov 13 '16 at 13:27