Way to implement nested controls?
Following the object oriented design I'd like to encapsulate my UI into separate UI elements. For this I'd like to create custom UserControls. This of course provides the challenge to use methods from the PluginControlBase like ExecuteMethod. I'd like a way to implement nested controls and have them all have the ability to do what a PluginControlBase can in terms of XRM connectivity and XTB interactivity.
Creating a new control and making it derive from PluginControlBase does compile, but of course does not work since whatever initialization is done on the default derivation instance of PluginControlBase when the tool is being opened is not performed here.
Passing things like the ExecuteMethod as an Action into a UserControl and calling it this way also does not work since at runtime an error will occur stating that the method is not found.
Code like this:
public partial class pluginCtrl : PluginControlBase
{
private void onLoad(object sender, EventArgs e)
{
// Pass the Executemethod from this PluginControlBase to the custom UserControl.
myUserControl.Init(ExecuteMethod);
}
}
public class MyUserControl : UserControl
{
private Action<Action> _executeMethod;
internal void Init(Action<Action> executeMethod)
{
// Store the Action for later use.
_executeMethod = executeMethod;
}
private void onBtnClick(object sender, EventArgs e)
{
// Call the action which is essentially ExecuteMethod from the parent PluginControlBase. This will raise the exception below.
_executeMethod(DoTheThing);
}
private void DoTheThing() { /* ... */ }
}
The error message is:
Unable to find method pluginCtrl.DoTheThing
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at XrmToolBox.New.NewForm.<ManageConnectionControl>b__68_2(Object sender, ConnectionSucceedEventArgs e)
at McTools.Xrm.Connection.ConnectionManager.SendSuccessMessage(IOrganizationService service, List`1 parameters)
at McTools.Xrm.Connection.WinForms.FormHelper.AskForConnection(Object connectionParameter, Action`1 preConnectionRequestAction)
at Tc.CrmOnPremBridge.MigrationsXtbTool.Controls.DispatchStatusMigration.migrateBtn_Click(Object sender, EventArgs e) in C:\Users\dschmid\Source\Repos\CRM.OnPremBridge\Tc.CrmOnPremBridge.MigrationsXtbTool\Controls\DispatchStatusMigration.cs:Zeile 30.
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at XrmToolBox.Program.Main(String[] args)
Now, the code does work if I change this line:
_executeMethod(DoTheThing);
to this:
_executeMethod(() => DoTheThing());
So I can live with that for now.
Still, I'd like to see a way to do this the clean way, maybe even a new chapter in the documentation. If I missed it please point it out to me.
Hi, thanks for reporting this.
Honestly, I'm not so good developer so I could fix this issue myself. But a pull request that would handle it could be nice.