[Solved] Add Actions from Database

Apr 27, 2015 at 8:11 AM
Edited Apr 27, 2015 at 8:14 AM
Hello,

I have create a routine to get the data for action from a database after the login and retrieve the Userrights for the user (I want to implement that the admin can menuentries "hide" for some users or application-usergroups)
                    ctlrAction = Split(mnuEntry.ControllerAction, "@")
                    Actions.Add(New ViewAction(mnuEntry.Text,
                                               category:=mnuGroup.Name,
                                               execute:=Function(a, o) Controller.Action(ctlrAction(0).ToString, ctlrAction(1).ToString)) With { _
                               .ToolTipText = mnuEntry.Description,
                               .Significance = ViewActionSignificance.AboveNormal,
                               .BrushResourceKey = mnuEntry.BrushName})

                    If NeededAssemblies.Contains(mnuEntry.LoadAssemblyName) = False Then
                        NeededAssemblies.Add(mnuEntry.LoadAssemblyName)
                    End If
After collect all actions for a specific UI i add the assemblies to my AppDomain
        For Each DllName In NeededAssemblies
            Try
                ApplicationEx.RegisterSecondaryAssembly(DllName)
            Catch ex As Exception
                NLOGLOGGER.Error(ex.Message)
            End Try

        Next
        Controller.ReloadControllers()
The Controller-Class I have extent with follwing code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CODE.Framework.Wpf.Mvvm
{
    partial class Controller
    {
        /// <summary>
        /// Clear the controllerslist
        /// </summary>
        public static void ClearControllers()
        {
            _controllers.Clear(); 
        }

        /// <summary>
        /// Clear the current Controllerlist and rpopulate the controllers
        /// </summary>
        public static void ReloadControllers()
        {
            _controllers.Clear();
            PopulateControllers();
        }

    }
}
Now I have following problem: All my actions will be linked to the last readed Execute-Command.

Do you know what can be the problem and how can i solve it?
Coordinator
Apr 30, 2015 at 7:39 AM
Hmmm... I am not totally sure I follow to be honest.

Is your problem that this doesn't work?
Controller.Action(ctlrAction(0).ToString, ctlrAction(1).ToString)
I would think that most likely, the ctlrAction enclosure gets reset to the last item in the list.

BTW: If you want to hide menu items from certain users, you can use the built-in user-role feature that each ViewAction has.


Markus
May 4, 2015 at 8:13 AM
Hello Markus,

I have create a small demo application to reproduce the behavior. How can I send it to you? Which way you prefer?

I hope you can see, what I doing wrong ;-)

Michael
Coordinator
May 4, 2015 at 10:14 AM
You can email it to me: megger@eps-software.com

Markus
May 8, 2015 at 4:42 PM
Edited May 8, 2015 at 4:45 PM
I have found out what the reason is - but I dont found a solution yet.

The problem is the Lambda-Expression. The should be
execute:=Function(a, o) Controller.Action("Options", "AllOverSettings") 
but the result of my is the define formular-text.
execute:=Function(a, o) Controller.Action(ctlrAction(0).ToString, ctlrAction(1).ToString)
So they didn´t can work properly.

I need a way to replace the paramters with the values. I hope someone have a good idea for that ;-)

Thanks
Michael
May 8, 2015 at 5:41 PM
The solution ist the string-construction:
execute:=Function(a, o) Controller.Action("" & ctlrAction(0).ToString & "", "" & ctlrAction(1).ToString & ""
Coordinator
May 8, 2015 at 8:35 PM
Hello!

I saw your email, but I haven't had a chance to take a look yet. Been quite busy with several different deadlines lately.

Anyway: As far as I can tell from this, the root-cause of the problem is that the enclosure created for the lambda expression (the "ctrlAction" variable) is incorrect when this actually executes. I assume this is due to the whole thing running in a loop and thus the variable getting updated. In other words, if you do something like this, then it is probably wrong:
Dim action as BlaBla
for x = 1 to 10
   action = myActions(x)
   someObject.DoSomethingWithLambda += l => action.YadaYada()
end for
In this case, I would think the action variable to be made an enclosure for the lambda expression. As a result, whenever the lambda expression really executes (for instance, when the action is triggered), then it would AT THAT POINT IN TIME use the value of the enclosure ("action"), which is now the 10th action, rather than the one you really want.

So the question is how to force an enclosure that is correct?

I think the method you discovered with adding an empty string forces the system to create an internal enclosure that is unique to every iteration of the loop. Another approach would probably be something like this:
for x = 1 to 10
   Dim action = myActions(x)
   someObject.DoSomethingWithLambda += l => action.YadaYada()
end for
This way, the action-variable should be uniquely created for each iteration and thus there should be multiple independent enclosures that have the correct value.

I don't remember all the rules of enclosure creation by heart, but I think you will find the solution to be something along those lines.


Markus