How To Make An Admin Panel To Controll Every Controller In My App.

Amr_Ali 136 Reputation points
2020-12-14T10:13:05.207+00:00

Hi all,
This question is strange, i think that . But i had to ask it before.....
Anyway , My clients asked me to fix some code in my apps. for example (I have to make a date changeable not fixed" In some Forms i made the datetimepicker takes the today date only and can't change to insure that the process done in the current date of Bill creation" But the client change his mind and want me to change this scenario to set the datetimepicker changeable to any date he want)
this so good and i can change it to whatever he wants .
But the question here is
Why do i have to make build to my app. every time and uninstall my app. from his machine and then install it again after any new changes to my app. ???
How can i make a Form (say for example "Admin Panel") to enable me to make any changes in the run time without need to uninstall the app. from the client machine ?
Can i use XML file to perform this mission and how ?
I want every controller in my app. obeying to this strategy .....
Any suggestions ............................

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,644 questions
0 comments No comments
{count} votes

Accepted answer
  1. Karen Payne MVP 35,366 Reputation points
    2020-12-17T11:12:43.84+00:00

    @Amr_Ali

    How can i add a new controls in the form1 and where can i write any methods or functions ??

    I'm sure it's possible to some extent but in 20 years of coding never had the need for this and would think this would need to run off some dynamic script. Although not an answer the following can give you a clue to the complexities you will face.

    1 person found this answer helpful.

5 additional answers

Sort by: Most helpful
  1. Karen Payne MVP 35,366 Reputation points
    2020-12-14T13:06:44.74+00:00

    Hello @Amr_Ali

    If the following is not what you care for then please provide more details.

    In regards to using XML, yes this is possible so long as you can write code in the application that can follow settings in the XML but another idea is to use a Json file instead as using Json when setup to read everything is strongly typed while XML is not.

    I have an example which controls unseen operations, in this case to log information to a log file. Below Helper class reads information from a Json file using Json.Net library into an instance of a class then in code we can ask for UsingLogging.

    JSON

    {  
      "GeneralSettings": {  
        "LogExceptions": false,  
        "DatabaseSettings": {  
          "DatabaseServer": ".\\SQLEXPRESS",  
          "Catalog": "NorthWind2020",  
          "IntegratedSecurity": true,  
          "UsingLogging": true  
        },  
        "EmailSettings": {  
          "Host": "smtp.gmail.com",  
          "Port": 587,  
          "EnableSsl": true,  
          "DefaultCredentials": false,  
          "PickupDirectoryLocation": "MailDrop"  
        }  
      }  
    }  
    

    Code

    Protected Overrides Sub OnConfiguring(ByVal optionsBuilder As DbContextOptionsBuilder)  
    	If Not optionsBuilder.IsConfigured Then  
      
    		If Helper.UseLogging() Then  
    			optionsBuilder.UseSqlServer(Helper.ConnectionString()).EnableSensitiveDataLogging().EnableDetailedErrors().LogTo(_logStream.WriteLine)  
    		Else  
    			optionsBuilder.UseSqlServer(Helper.ConnectionString())  
    		End If  
      
    	End If  
    End Sub  
    
    • Classes to store information are found here in my GitHub repository.
    • The following class (also in the same repository) provides code to read the json file above with a small example to write back to the json file.
    • Since the class in the last bullet uses shared methods it's easy to obtain information any place in your code to respond to and get changes in code logic where the settings may change in a admin form.
    • The Admin form reads and changes settings
    • No matter if there are changes or just reading, at application startup you can read settings into a singleton class or a code module and other parts of the code can use what was read at startup.

    Control changes

    The following is from the second bullet above which indicates how to read and respond to if changes are made at runtime to the underlying json file.
    47965-a1.png

    Below shows a class project (found here) which is portable to any project for reading json

    47982-a1a.png

    The following is an example (has no ties to the code above other than it uses the exact same logic mention above) where the top form is accessed from the "Misc" menu, user makes changes and then when actions are performed they use setting from the json file.

    47919-a2.png

    Redirecting assembly versions

    Even though the following may not suit your needs it is at least worth knowing about which does need a update installation is working with versions of a DLL which explained here.

    Part of the solution is to update the .config file .e.g.

    <configuration>  
       <runtime>  
          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">  
           <dependentAssembly>  
             <assemblyIdentity name="myAssembly"  
                               publicKeyToken="32ab4ba45e0a69a1"  
                               culture="en-us" />  
             <bindingRedirect oldVersion="1.0.0.0"  
                              newVersion="2.0.0.0"/>  
           </dependentAssembly>  
          </assemblyBinding>  
       </runtime>  
    </configuration>  
    
    1 person found this answer helpful.

  2. Karen Payne MVP 35,366 Reputation points
    2020-12-15T20:15:37.75+00:00

    Hello @Amr_Ali

    I don't have time to do a great code sample, best I can do is give you something that I've been working on. Keeping this simple, form control properties are set in form shown event while updates are done in form closing event (you would use a button). There is no assertion e.g. make sure say a string property that is required is not empty as that would simply cloud what there is to learn from the Json operations.

    Screenshot

    48358-emailsettings.png

    JSON

    {  
      "GeneralSettings": {  
        "LogExceptions": false,  
        "DatabaseSettings": {  
          "DatabaseServer": ".\\SQLEXPRESS",  
          "Catalog": "NorthWind2020",  
          "IntegratedSecurity": true,  
          "UsingLogging": true  
        },  
        "EmailSettings": {  
          "Host": "smtp.gmail.com",  
          "Port": 587,  
          "EnableSsl": true,  
          "DefaultCredentials": false,  
          "PickupDirectoryLocation": "MailDrop"  
        }  
      }  
    }  
    

    Form code

    Read JSON and then sets control values

    Imports ConfigurationHelper  
    Imports ConfigurationHelper.Classes  
    Imports System.ComponentModel  
      
    Public Class Form1  
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown  
      
            Dim emailSettings = GeneralSettings().GeneralSettings.EmailSettings  
      
            HostTextBox.Text = emailSettings.Host  
            EnableSslCheckBox.Checked = emailSettings.EnableSsl  
            DefaultCredentialsCheckBox.Checked = emailSettings.DefaultCredentials  
        End Sub  
      
        Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing  
      
            Dim current = GeneralSettings()  
            current.GeneralSettings.EmailSettings.Host = HostTextBox.Text  
            current.GeneralSettings.EmailSettings.EnableSsl = EnableSslCheckBox.Checked  
            current.GeneralSettings.EmailSettings.DefaultCredentials = DefaultCredentialsCheckBox.Checked  
            Helper.Update(current)  
      
        End Sub  
      
        Private Function GeneralSettings() As GeneralSettingsRoot  
            Return Helper.AllSettings()  
        End Function  
      
    End Class  
    

    Backend code

    Class project, read code, update code

    1 person found this answer helpful.

  3. Amr_Ali 136 Reputation points
    2020-12-16T18:28:30.607+00:00

    **I DON'T WHY I CAN'T POST A COMMENT **

    OK it worked well, but it deals with values only(I think that) not with writing code....
    I want to save and write code in run time ..
    Can i save Subroutines in the JSON file . Just ask ,really i don't know ,
    Your code is so nice with some modifications but i don't know how to do it ....
    Could you feed my by an example with many codes or controllers ...
    OK sure textbox is like combobox or checkbox but what about DataGridView and some other controller, What about write Funcnctions and Subs , What about changing the position of an controller say for example "changing the postion of an textbox from one place to another in the same form" , My needs are to facilitate the maintenance process after finishing the project, I will be able to manage my code from the client site no need to say ("I will test it in my site then i will come to your site to fix it") The whole modifications will perform from the GUI "Admin panel" on the client machine,,
    Really i appreciated your efforts ,


  4. Karen Payne MVP 35,366 Reputation points
    2020-12-16T21:20:58.473+00:00

    @Amr_Ali This is all I can do presently as mentioned limited time.

    Class for getting control types

    (taken from my C# gist)

    ''' <summary>  
    ''' Collection of language extenstion methods for working with form controls.  
    ''' </summary>  
    Public Module ControlExtensions  
      
    	''' <summary>  
    	''' Provides access to all controls on a form including  
    	''' controls within containers e.g. panel and group-box etc.  
    	''' </summary>  
    	''' <typeparam name="T"></typeparam>  
    	''' <param name="control"></param>  
    	''' <returns></returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Iterator Function Descendants(Of T As Class)(control As Control) As IEnumerable(Of T)  
    		For Each child As Control In control.Controls  
      
    			Dim currentChild = TryCast(child, T)  
    			If currentChild IsNot Nothing Then  
    				Yield currentChild  
    			End If  
      
    			If child.HasChildren Then  
    				For Each descendant As T In child.Descendants(Of T)()  
    					Yield descendant  
    				Next  
    			End If  
    		Next  
      
    	End Function  
    	''' <summary>  
    	''' Get all TextBox controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of TextBoxes or an empty list if no TextBoxes on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function TextBoxList(control As Control) As List(Of TextBox)  
    		Return control.Descendants(Of TextBox)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all TextBox controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of TextBoxes or an empty list if no TextBoxes on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function ListViewViewList(control As Control) As List(Of ListView)  
    		Return control.Descendants(Of ListView)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all CheckBox controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of CheckBox or an empty list if no CheckBox on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function CheckBoxList(control As Control) As List(Of CheckBox)  
    		Return control.Descendants(Of CheckBox)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all ComboBox controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of ComboBox or an empty list if no ComboBox on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function ComboBoxList(control As Control) As List(Of ComboBox)  
    		Return control.Descendants(Of ComboBox)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all ListBox controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of ListBox or an empty list if no ListBox on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function ListBoxList(control As Control) As List(Of ListBox)  
    		Return control.Descendants(Of ListBox)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all Panel controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of Panel or an empty list if no Panel on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function PanelList(control As Control) As List(Of Panel)  
    		Return control.Descendants(Of Panel)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all GroupBox controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of GroupBox or an empty list if no GroupBox on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function GroupBoxList(control As Control) As List(Of GroupBox)  
    		Return control.Descendants(Of GroupBox)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all Button controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of Button or an empty list if no Button on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function ButtonList(control As Control) As List(Of Button)  
    		Return control.Descendants(Of Button)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get all RadioButton controls from specified control  
    	''' </summary>  
    	''' <param name="control">Desired control which can be a form or a control like a panel or GroupBox on a form</param>  
    	''' <returns>List of RadioButton or an empty list if no RadioButton on control</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function RadioButtonList(control As Control) As List(Of RadioButton)  
    		Return control.Descendants(Of RadioButton)().ToList()  
    	End Function  
    	''' <summary>  
    	''' Get selected/checked RadioButton for a control such as a panel, group box or form  
    	''' </summary>  
    	''' <param name="control">control, form, panel or group box</param>  
    	''' <param name="Checked">True false, defaults to true</param>  
    	''' <returns>One checked Radio button or a empty value</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function RadioButtonChecked(control As Control, Optional ByVal Checked As Boolean = True) As RadioButton  
    		Return control.Descendants(Of RadioButton)().ToList().FirstOrDefault(Function(radioButton) radioButton.Checked = Checked)  
    	End Function  
    	''' <summary>  
    	''' Control names for a control  
    	''' </summary>  
    	''' <param name="controls">Controls</param>  
    	''' <returns>names for controls</returns>  
    	<Runtime.CompilerServices.Extension>  
    	Public Function ControlNames(controls As IEnumerable(Of Control)) As String()  
    		Return controls.Select(Function(control) control.Name).ToArray()  
    	End Function  
    End Module  
    

    Control container

    Public Class ControlContainer  
        Public Property FormName() As String  
        Public Property Text() As String  
        Public Property Location As Point  
        Public Property Name As String  
        Public Property Size As Size  
        Public Property Anchor As AnchorStyles  
        Public Property TabIndex As Integer  
        Public Property Type As Type  
        Public Property Checked() As Boolean  
      
    End Class  
    

    Class to store details

    Public Class FormOperations  
        Private Shared Container As New List(Of ControlContainer)  
      
        Public ReadOnly Property HasControls() As Boolean  
            Get  
                Return Container.Count > 0  
            End Get  
        End Property  
        Public Shared Sub Collect(sender As Form)  
      
            Container.Clear()  
      
            Dim itemList As New List(Of ControlContainer)  
      
            sender.ButtonList.ForEach(Sub(button)  
                                          itemList.Add(New ControlContainer() With {  
                                            .Type = GetType(Button),  
                                            .Text = button.Text,  
                                            .Anchor = button.Anchor,  
                                            .Location = button.Location,  
                                            .TabIndex = button.TabIndex,  
                                            .Name = button.Name,  
                                            .FormName = sender.Name  
                                }  
                             )  
                                      End Sub)  
      
            sender.CheckBoxList.ForEach(Sub(checkBox)  
                                            itemList.Add(New ControlContainer() With {  
                                                .Type = GetType(CheckBox),  
                                                .Anchor = checkBox.Anchor,  
                                                .Location = checkBox.Location,  
                                                .TabIndex = checkBox.TabIndex,  
                                                .Name = checkBox.Name,  
                                                .Checked = checkBox.Checked,  
                                                .FormName = sender.Name  
                                }  
                             )  
                                        End Sub)  
      
            Dim buttons = itemList.Where(Function(item) item.Type Is GetType(Button)).ToList()  
            Dim checkBoxes = itemList.Where(Function(item) item.Type Is GetType(CheckBox)).ToList()  
      
            Container.AddRange(buttons)  
            Container.AddRange(checkBoxes)  
        End Sub  
      
        Public Shared Function GetByForm(sender As String) As List(Of ControlContainer)  
            Return Container.Where(Function(item) item.FormName = sender).ToList()  
        End Function  
      
      
    End Class  
    

    Serialize/deserialize

    Can be done with Serialize and Deserialize method of JSON.NET via a NuGet package install.

    Install-Package Newtonsoft.Json -Version 12.0.3