Threads

Jan 13, 2009 at 11:08 AM
Hi,

Is it possible to use threads for processing some long process with this framework, for instance, having a progress bar (View) being updated by a worker thread (Controller)?
If so, is it better to use a ViewControl object as the View (progressBar) and its corresponding Controller in a separate thread?

Thanks,

Gonçalo.
Coordinator
Jan 13, 2009 at 1:44 PM
As you know the main idea when using a separate threads when updating the UI thread is to use the Control.Invoke. The framework includes some check if the Invoke is required and then invokes an update. Take a look ViewControl and ViewForm classes they have the following:

public void UpdateView(string key)

{

     if (!this.InvokeRequired)

     {

          OnUpdateView(key);

     }

     else

     {

         this.Invoke(new Action<string>(OnUpdateView), key);

     }

}     

public ViewDataDictionary ViewData

{

     get

     {

         if (_viewData == null)

         {

             _viewData = new ViewDataDictionary();

         }

         return _viewData;

     }

     set

     {

         if (!this.InvokeRequired)

         {

             _viewData = value;

         }

         else

         {

             this.Invoke(new Action<ViewDataDictionary>(SetViewData), value);

         }

     }

}

So if you are going to be using these they should work. However in the case if you are using events to notify the view of the changes in the model, you would need to handle this scenario yourself.

HTH... Alex

Jan 13, 2009 at 8:30 PM
Hi Alex,

I see..
It would be nice to have that feature in the future.

Thanks,

Gonçalo
Coordinator
Jan 13, 2009 at 8:39 PM
Could you describe your scenario in more detail?
Jan 16, 2009 at 1:35 PM
Hi Alex, sorry for the late response,

I was thinking of a scenario where you have a form (modal or not) with a progress bar and using events to notify the progressBar (view) using thedelegates for passing typed objects.
To me, the events aproach makes more sense, that's why thread support for the events would be nice.

Gonçalo


Coordinator
Jan 16, 2009 at 2:38 PM
Unfortunatelly there is no way to know when and where from a certain event would be called. All what the framework does is automatically hooks up the declared event into event handler. It would be a responsibility of the implementor of the event handler to write the code that handles the scenarios of updating the UI from a different thread.

HTH... Alex
Jan 16, 2009 at 4:49 PM
Edited Jan 19, 2009 at 8:01 AM
Hummm, i see.
(Offtopic)
I thought of a way to display those OnUpdateView in a more clean way using Attributes.
Instead of using code like this:

{code:c#}
if (key.Equals("UpdateProgress"))
{
this.progressControl.NextPosition(this.ViewData["ProgressMessage"].ToString());
}
else if (key.Equals("EndProgress"))
{
this.btnStart.Enabled = true;
this.mnuBack.Enabled = true;
this.progressControl.Hide();
}

It would appear something like this: (which is similar to the current implementation of the Events)

[ViewKey("EndProgress")]
private void UpdateProgressBar()
{
this.progressControl.NextPosition(this.ViewData["ProgressMessage"].ToString());
}

[ViewKey("EndProgress")]
private void EndProgress()
{
this.btnStart.Enabled = true;
this.mnuBack.Enabled = true;
this.progressControl.Hide();
}

{/code:c#}

What do you think?
Coordinator
Jan 21, 2009 at 3:58 PM
Thanks for your suggestion. However I don't see an easy way to implement it.

-Alex
Jan 21, 2009 at 6:26 PM
It could be done like this:

A simple Attribute:
[AttributeUsage(AttributeTargets.Method)]
public class UpdateKeyAttribute : Attribute
    {
        private readonly string _updateKey = String.Empty;
        public string UpdateKey
        {
            get
            {
                return _updateKey;
            }
        }

        public UpdateKeyAttribute(string updateKey)
        {
            _updateKey = updateKey;
        }
    }

On abstract Controller.cs

Implement OnViewStateChange(string key)
Before:

protected virtual void OnViewStateChanged(string key)
        {

        }

After:
protected void OnViewStateChanged(string key)
        {
            MethodInfo methodToInvoke = null;
            MethodInfo[] methods = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

            foreach (MethodInfo mInfo in methods)
            {
                object[] attribs = mInfo.GetCustomAttributes(typeof(UpdateKeyAttribute), false);
                if (attribs.Length > 0)
                {
                    UpdateKeyAttribute attribute = attribs[0] as UpdateKeyAttribute;
                    if (attribute.UpdateKey.Equals(key))
                    {
                        methodToInvoke = mInfo;
                        break;
                    }
                }
            }

            methodToInvoke.Invoke(this, null);
        }

On ViewForm.cs same as the Controller.cs

Before:
protected virtual void OnUpdateView(string key)
{
}

After:
protected void OnUpdateView(string key)
        {
            MethodInfo methodToInvoke = null;
            MethodInfo[] methods = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

            foreach (MethodInfo mInfo in methods)
            {
                object[] attribs = mInfo.GetCustomAttributes(typeof(UpdateKeyAttribute),false);
                if (attribs.Length > 0)
                {
                    UpdateKeyAttribute attribute = attribs[0] as UpdateKeyAttribute;
                    if (attribute.UpdateKey.Equals(key))
                    {
                        methodToInvoke = mInfo;
                        break;
                    }
                }
            }

            methodToInvoke.Invoke(this, null);
        }

Of course this is using Reflection in Runtime to find the method to invoke.
Ideally it would do this search in the construction of the controller and the view, but for that we would need a a list of Action, or events.

(Offtopic: how do i format my code here at codeplex? )


Coordinator
Jan 21, 2009 at 6:31 PM
Edited Jan 21, 2009 at 6:32 PM
Yes I thought of this way, but I would like to avoid using Reflection if it's possible - it's really slow on the device. But you are free to modify the code and use it for your needs.

-Alex
Jan 21, 2009 at 7:08 PM
How about a more simple solution?

On the constructor of the View

private field:

private Dictionary<string,Action> = null;

public ViewForm()
        {
            _listActions = new Dictionary<string, Action>();
            MethodInfo[] methods = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

            foreach (MethodInfo mInfo in methods)
            {
                object[] attribs = mInfo.GetCustomAttributes(typeof(UpdateKeyAttribute), false);
                if (attribs.Length > 0)
                {
                    UpdateKeyAttribute attribute = attribs[0] as UpdateKeyAttribute;
                    _listActions[attribute.UpdateKey] = (Action)Delegate.CreateDelegate(typeof(Action), this, mInfo);
                }
            }
        }

private void OnUpdateView(string key)
{
            _listActions[key].Invoke();
}

Still uses Reflection but only in the construction of the View, the Dictionary stores a Key, Action relation. :)