I am working on UI where i have some controls like textbox, button, radiobutton and more.
On some specific business workflows i have to play with my controls and set their state as enable/disable or set visibility of them.
When i do this my whole UI code behind (xaml.cs) scattered with controls enabling and disabling.
i want to write a single method which is completely responsible for handling the state of my UI controls.
Currently what i have done is - making a single function which take the operation as parameter and then based on operation i am playing with my controls.
For example:
private const string ADD_OPERATION = "Add";
private const string MODIFY_OPERATION = "Modify";
private const string DELETE_OPERATION = "Delete";
-------------------------------------------------------
/// <summary>
/// Method for disabling controls present on current screen
/// based on various operations like add, delete, edit identity
/// </summary>
private void EnableOrDisableIdentityControl(string operation)
{
switch (operation)
{
case ADD_OPERATION:
this.EditIdentificationGroupBox.IsEnabled = true;
this.AddUpdateIdentificationButton.IsEnabled = true;
this.RelatedEntitiesGridFooter.IsAddButtonEnabled = false;
this.RelatedEntitiesGridFooter.IsEditButtonEnabled = false;
this.RelatedEntitiesGridFooter.IsDeleteButtonEnabled = false;
this.IdentificationDataGrid.IsEnabled = false;
break;
case MODIFY_OPERATION:
this.EditIdentificationGroupBox.IsEnabled = true;
// Disable identity grid
this.IdentificationDataGrid.IsEnabled = false;
this.RelatedEntitiesGridFooter.IsAddButtonEnabled = false;
this.RelatedEntitiesGridFooter.IsEditButtonEnabled = false;
this.RelatedEntitiesGridFooter.IsDeleteButtonEnabled = false;
this.EditIdentificationGroupBox.Focus();
break;
case DELETE_OPERATION:
this.EditIdentificationGroupBox.IsEnabled = false;
break;
default:
this.EditIdentificationGroupBox.IsEnabled = false;
if (this.IdentificationDataGrid.Items.Count == 0)
{
this.RelatedEntitiesGridFooter.IsAddButtonEnabled = true;
this.RelatedEntitiesGridFooter.IsEditButtonEnabled = false;
this.RelatedEntitiesGridFooter.IsDeleteButtonEnabled = false;
}
else
{
this.RelatedEntitiesGridFooter.IsAddButtonEnabled = true;
this.RelatedEntitiesGridFooter.IsEditButtonEnabled = true;
this.RelatedEntitiesGridFooter.IsDeleteButtonEnabled = true;
}
break;
}
}
I want to know is there is any better approach for effectively handling controls state in code behind?
I am not sure using winform way of code-behind handling is right way to go. WPF was specifically designed to get rid of tight coupling of view with code-behind. I would suggest to use MVVM pattern (Model-View-ViewModel) intended for WPF which would solve all these issues you mentioned.
Related
I am trying to repeat an exercise from the book ("C# 7.0: All-in-One-for-Dummies") which shows how authentification and authorization works in WinForms. And everything compiles and there are no issues during runtime but it doesn't works as intended.
Let me explain in details:
I have three buttons (Sales, Accountancy and HR) and I have the code which allows only the member of the appropriate group to be able to see this button (by the way, buttons' .Visible = false). I made an additional User (with the user rights and not administrator) and Groups for experimentation and added this User to each Group consequently. What I mean. I added the user to the group and then check the result. After this I deleted user from the group and add him to the next one. And so on.
The result is that sometimes I can see all buttons and some times I can't see only one button (but not the intended one) and it seems like my code doesn't affect a thing or affect it in a weird manner. I have no idea what is going on. My Windows is 7 Home Advanced and I am working with groups and users via CMD with net localgroup and net user. I read Microsoft description for IsInRole method and it seems like I did everything correct because if you indicate string with the name of the group it means the exact group in your Windows. Here is the code itself:
using System;
using System.Windows.Forms;
using System.Security.Principal;
namespace AuthentificationAndAuthorization
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
WindowsIdentity userIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal userRights = new WindowsPrincipal(userIdentity);
if (userRights.IsInRole("Accountancy")) AccountingButton.Visible = true;
else if (userRights.IsInRole("Sales")) SalesButton.Visible = true;
else if (userRights.IsInRole("HR")) ManagerButton.Visible = true;
else if (userRights.IsInRole(WindowsBuiltInRole.Administrator)) AccountingButton.Visible = true; SalesButton.Visible = true; ManagerButton.Visible = true;
}
}
}
Thanks in advance for any suggestions!
Here's your problem: don't use if without braces. It's what caused Apple's 2014 iOS security nightmare.
Change this:
if (userRights.IsInRole("Accountancy")) AccountingButton.Visible = true;
else if (userRights.IsInRole("Sales")) SalesButton.Visible = true;
else if (userRights.IsInRole("HR")) ManagerButton.Visible = true;
else if (userRights.IsInRole(WindowsBuiltInRole.Administrator)) AccountingButton.Visible = true; SalesButton.Visible = true; ManagerButton.Visible = true;
to this:
if (userRights.IsInRole("Accountancy"))
{
this.AccountingButton.Visible = true;
}
else if (userRights.IsInRole("Sales"))
{
this.SalesButton.Visible = true;
}
else if (userRights.IsInRole("HR"))
{
this.ManagerButton.Visible = true;
}
else if (userRights.IsInRole(WindowsBuiltInRole.Administrator))
{
this.AccountingButton.Visible = true;
this.SalesButton.Visible = true;
this.ManagerButton.Visible = true;
}
....or better yet, do this:
Boolean isAdmin = userRights.IsInRole(WindowsBuiltInRole.Administrator);
this.AccountingButton.Visible = userRights.IsInRole("Accountancy") || isAdmin;
this.SalesButton .Visible = userRights.IsInRole("Sales") || isAdmin;
this.ManagerButton .Visible = userRights.IsInRole("HR") || isAdmin;
Also, avoid using magic strings: if you move those role-names to be const String values in a static class then your code will be easier to maintain in future.
After I tried some debugging and did nothing else it started to work as I expect all of a sudden. This is cryptic...Also I found that builin Administrator can see all buttons no matter what you code tells. Ok. Nevermind.
I am trying to remake my C#/WPF take on the Simon game by making it more clean and use classes now that I finally understand classes. Before I ask my question - here is some sample code from my old version as a reference.
public MainWindow()
{
InitializeComponent();
RedButton.IsEnabled = false;
BlueButton.IsEnabled = false;
GreenButton.IsEnabled = false;
YellowButton.IsEnabled = false;
}
//Use TextBlock clearing to say "Watch the pattern", "Your Turn" and then an empty box between games
private void StartButton_Click(object sender, RoutedEventArgs e)
{
_IsError = false;
RedButton.IsEnabled = true;
BlueButton.IsEnabled = true;
GreenButton.IsEnabled = true;
YellowButton.IsEnabled = true;
StartButton.IsEnabled = false;
if (randomPattern.Count == 0)
{
randomPattern.Add(random.Next(0, 4));
randomPattern.Add(random.Next(0, 4));
}
StatusBox.Text = "Watch the Pattern.";
ShowPattern();
}
So, my question is: Would it be good practice for me to use IsElement as a property/attribute of class "Buttons" instead of writing all of their statements out individually? And if I should add them to the class, I think my next question comes down to - how would I implement it into the class? I know simply typing only "IsEnabled = <T/F>" won't do anything.
EDIT:
To show you what I mean:
Should I have IsEnabled as a class property like such:
class Button {
IsEnabled = false;
}
var greenButton = new Button()
//Some code that lets the player start the game by clicking a button
greenButton.IsEnabled = true;
Or should I keep my IsEnabled statements outside of a class like in my old version of the code? Note - my old version of the code, there are no classes that I made - only functions.
IsEnabled should be placed into Button class as it is property or feature of button.
public class Button {
public IsEnabled { get; set; }
}
The above class has high cohesion as it is focused on what it should be doing. It has only methods/properties, fields relating to the intention of the class.
I'm using the exact same code multiple times and I thought that it would be quite inefficient to just copy/paste everything. Is there a way for let's say button2 to use the exact same code as button1 without copy/pasting everything?
Some of my code is very big, that's why I'm asking.
I'm aware of this for example:
private TabPage T
{
get { return (t.SelectedTab); }
}
However I have no idea how to make this work for this: (Yes, there are multiple ways to enable Full Screen mode in my application)
if (FormBorderStyle != FormBorderStyle.None)
{
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Normal;
WindowState = FormWindowState.Maximized;
p1.BackColor = Color.White;
p2.BackColor = Color.White;
TopMost = true;
c2.Visible = false;
Wi.Visible = false;
t1.Visible = false;
F.Text = "Exit Full Screen";
t2.Text = "Exit Full Screen";
}
else
{
FormBorderStyle = FormBorderStyle.Sizable;
if (Environment.OSVersion.Version.Build >= 7000)
{
if (DWM.DwmIsCompositionEnabled())
{
Color c = Color.FromArgb(255, 221, 220, 220);
TransparencyKey = c;
p1.BackColor = c;
p2.BackColor = c;
MARGINS mr = new MARGINS();
mr.T = 1800;
IntPtr h = Handle;
int result = DwmExtendFrameIntoClientArea(h, ref mr);
}
}
TopMost = false;
Wi.Visible = true;
t1.Visible = true;
F.Text = "Full Screen";
t2.Text = "Full Screen";
}
You can also put the code in a separate method and call the method in both event handlers making no confusion about that it does and for who. they can see exactly which button calls what method or code. In this case it would be the same method.
Just apply the same event handler to both buttons. This can be done either through simply typing the name of the method in the events tab of the designer, or through manually adding the event handler upon construction.
It's generally a good idea in such cases to also refactor the method name into something that makes sense for both buttons to call. If clicking button2 fires button1_click some other coders might be confused. If both buttons fire a MakeFullscreen method then it's less confusing.
I'm creating a interface for a application at the moment. Background are all 1x1 pixel. In design time the interface is super slow (visual studio 2012). Moving components is super laggy. If I run the application it takes about 10 seconds for the interface to load.
Some parts of the interface can be hidden. Ones they become visible again they take time to build up / load part by part.
How can I improve this and make the interface much smoother / loading faster?
Source code:
namespace WindowsFormsApplication1
{
public partial class MapTool : Form
{
public int Pin_Berekenen = 0;
public int pin_Settings = 0;
public MapTool()
{
InitializeComponent();
BlackSetupUI();
panel_Berekenen.Visible = false;
panel_settings.Visible = false;
}
void BlackSetupUI()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Selectable, false);
pictureBox_RouteBerekenen.BackColor = Color.Transparent;
panel_Berekenen.BackColor = Color.Transparent;
pictureBox_settings.BackColor = Color.Transparent;
button_pin_berekenen.FlatAppearance.BorderSize = 0;
button_Berekenen.FlatAppearance.BorderSize = 0;
label_berekening1.Parent = pictureBox_bar;
label_berekening1.BackColor = Color.Transparent;
label_Berekening2.Parent = pictureBox_bar;
label_Berekening2.BackColor = Color.Transparent;
label_verschil.Parent = pictureBox_bar;
label_verschil.BackColor = Color.Transparent;
button_pin_settings.FlatAppearance.BorderSize = 0;
label_RouterBerekenen.Parent = pictureBox_bar;
label_Settings.Parent = pictureBox_bar;
pictureBox_settings.Parent = pictureBox_bar;
pictureBox_RouteBerekenen.Parent = pictureBox_bar;
pictureBox_innectis.Parent = pictureBox_bar;
label_innectis.Parent = pictureBox_bar;
}
void WhiteSetupUI()
{
}
private void MapTool_MouseClick(object sender, MouseEventArgs e)
{
if (Pin_Berekenen == 0)
{
panel_Berekenen.Visible = false;
}
else
{
return;
}
if (pin_Settings == 0)
{
panel_settings.Visible = false;
}
else
{
return;
}
}
private void button_pin_berekenen_Click(object sender, EventArgs e)
{
switch (Pin_Berekenen)
{
case 0:
Pin_Berekenen = 1;
button_pin_berekenen.Image = Properties.Resources.Pinned;
break;
case 1:
Pin_Berekenen = 0;
button_pin_berekenen.Image = Properties.Resources.Pin;
break;
default:
break;
}
}
private void button_pin_settings_Click(object sender, EventArgs e)
{
switch (pin_Settings)
{
case 0:
pin_Settings = 1;
button_pin_settings.Image = Properties.Resources.Pinned;
break;
case 1:
pin_Settings = 0;
button_pin_settings.Image = Properties.Resources.Pin;
break;
default:
break;
}
}
private void pictureBox_settings_MouseHover_1(object sender, EventArgs e)
{
panel_settings.Visible = true;
}
private void pictureBox_RouteBerekenen_MouseHover_1(object sender, EventArgs e)
{
panel_Berekenen.Visible = true;
}
}
}
I'm just designing the interface there is no data loaded with in this application as you can see.
It is hard to tell what exactly is your interface "doing". But here are some general tips:
You can preload something while showing splash screen (with or without progress) and then doing all time consuming work (to example, constructing all forms, parsing all configurations, caching graphics, etc). Or even put main application into dll and making exe-file small with the only splash screen.
You can optimize parent/child controls redrawing and layout operations (BeginUpdate/EndUpdate and such), so you don't waste time by calling unnecessary draw operation until it's a right time for it to happens. You can use double buffering, WS_EX_COMPOSITED.
If you have to much calculations, then perhaps something has to be virtualized (you display "fast placeholders" and after caculation replace them with real data) or cached.
You can use one of many tricks to simulate faster (as user can feel) operation: show a small part of data on screen, while prepare a much bigger portion of data in the memory (sort of virtual window), add some intelligent conclusions and caching (if user is moving left, then perhaps he want to continue that way, preload more data from left or, if user is moved right by 100 pixels, perhaps he will want to return, so don't unload that data yet).
Perhaps you have to much data what you have to profile it and optimize or even use C++ to write speed demanded parts in separate dll's.
Or maybe you should redesign your UI, split common parts into control, put nested things into user controls, etc, etc..
Hide all of them then when it is fully loaded, show it up
If you want to show animation, you can use Bunifu UI (paid)
EDIT: I see I'm getting a lot of downvotes on this post. I've tried to explain what I try to do, where my errors and in which direction want to go. I'm asking for insight in what I'm doing wrong. If you downvote; pleas tell me why, so I can improve the question. Thanks.
I'm creating an application where I have one main form, and several different User Controls which the user works on. This helps me splitting the code, managing the different parts of the program. And it would be easy to expand the application later on.
I'm trying to create a class where I manage the active controls I want to call one function in that class with as argument the form that should become active.
An image can illustrate how I try to setup this application. Note that the control manager class is not a seperate class in the code i show below, but a partial class of the mainform. Any tips on how to get it like in the image are very welcome :)
The class to manage all active forms looks like this: Please note that all user controls are just a user control with some buttons/textboxes etc on it. No code is added at all yet.
public partial class STP2Main
{
// I make each UserControl accessable for the whole class
SetupDeviceControl.SetupDevice SetupDev = new SetupDeviceControl.SetupDevice();
GenConfigFileControl.GenConfigFileControl GenConfFile = new GenConfigFileControl.GenConfigFileControl();
Monitoring.MonitoringControl Monitor = new Monitoring.MonitoringControl();
GenEncKeyControl.GenEncKeyControl GenEncKey = new GenEncKeyControl.GenEncKeyControl();
MenuControl.MenuControl MenuControl = new MenuControl.MenuControl();
public void SelectActiveWindow()
{
// Any active control should be hidden thats what this function does:
HideCurrentActiveControl();
// Check whether the window is already created
if (!WindowExists())
{ // if not created; create the windows:
switch (STP_Design.ProgramParameters.C.NextActiveControl)
{
case STP_Data.Data.SetupDeviceControl: // control 1:
STP_Design.ProgramParameters.C.CurrentActiveControl = STP_Data.Data.SetupDeviceControl;
STP_Design.ProgramParameters.C.SetupDeviceControlIsCreated = true;
SetupDev.Parent = this;
SetupDev.Location = new Point(3, 30);
SetupDev.Show();
SetupDev.BringToFront();
break;
case STP_Data.Data.MonitoringControl: //control 2:
STP_Design.ProgramParameters.C.CurrentActiveControl = STP_Data.Data.MonitoringControl;
STP_Design.ProgramParameters.C.MonitoringControlIsCreated = true;
Monitor.Parent = this;
Monitor.Location = new Point(3, 125);
Monitor.Show();
Monitor.BringToFront();
break;
case STP_Data.Data.MenuControl: // control 3
STP_Design.ProgramParameters.C.CurrentActiveControl = STP_Data.Data.MenuControl;
STP_Design.ProgramParameters.C.MenuControlIsCreated = true;
MenuControl.Location = new Point(3, 30);
MenuControl.Parent = this;
MenuControl.Show();
MenuControl.BringToFront();
break;
}
}
else
{ // window is already created so needs to be called to front again:
switch (STP_Design.ProgramParameters.C.NextActiveControl)
{
case STP_Data.Data.SetupDeviceControl:
STP_Design.ProgramParameters.C.CurrentActiveControl = STP_Data.Data.SetupDeviceControl;
SetupDev.BringToFront();
break;
case STP_Data.Data.MonitoringControl:
STP_Design.ProgramParameters.C.CurrentActiveControl = STP_Data.Data.MonitoringControl;
Monitor.Visible = true;
Monitor.BringToFront();
break;
case STP_Data.Data.AdvancedMenu:
STP_Design.ProgramParameters.C.CurrentActiveControl = STP_Data.Data.AdvancedMenu;
tabControl1.Visible = true;
tabControl1.BringToFront();
break;
case STP_Data.Data.MenuControl:
STP_Design.ProgramParameters.C.CurrentActiveControl = STP_Data.Data.MenuControl;
MenuControl.Visible = true;
MenuControl.BringToFront();
break;
}
}
btnMenu.BringToFront();
}
// some functions which are called above are not shown; not relevant for this question
}
What I experience is the following: I get no errors at all. But the controls simply not change at all. If I call a window, it is created only once, because I did make it as partial class of my Mainform. (I've tried a complete seperate class, which did result in errors with threading, As I am not an experienced c# programmer, I tried to avoid that using a partial class.)
I'll add another function; which does not do anything at all:
private void HideCurrentActiveControl()
{
switch (STP_Design.ProgramParameters.C.CurrentActiveControl)
{
case STP_Data.Data.SetupDeviceControl:
SetupDev.Visible = false;
break;
case STP_Data.Data.MonitoringControl:
tabControl1.Visible = false;
Monitor.Visible = false;
break;
case STP_Data.Data.GenConfFileControl:
GenConfFile.Visible = false;
break;
case STP_Data.Data.GenEncKeyControl:
GenEncKey.Visible = false;
break;
case STP_Data.Data.MenuControl:
MenuControl.Visible = false;
break;
case STP_Data.Data.AdvancedMenu:
tabControl1.Visible = false;
break;
default:
tabControl1.Visible = false;
break;
}
}
I've tried debugging this part of code and it executes the statements, but I see no changes at all.
I think I've shown what I am trying to do; and how I try to do that. My question is: How do I acces those forms so I can manage them from a seperate class (or in this case partial class of the main form).
Then I have this last function, which does some wierd things. Before I call the SelectActiveWindow() function I update the variable STP_Design.ProgramParameters.C.NextActiveControl to for example: ...AdvancedMenu. (this was before that ...MenuControl) But it does always show that it is still MenuControl. Nowhere in my code is something where I change that value besides right before I start the function. (I've also tried to make the nextcontrol as an argument of the function SelectActiveWindow() but this did the same)
private bool WindowExists()
{
switch (STP_Design.ProgramParameters.C.NextActiveControl)
{
case STP_Data.Data.SetupDeviceControl:
if (STP_Design.ProgramParameters.C.SetupDeviceControlIsCreated)
return true;
else
return false;
case STP_Data.Data.MonitoringControl:
if (STP_Design.ProgramParameters.C.MonitoringControlIsCreated)
return true;
else
return false;
case STP_Data.Data.GenConfFileControl:
if (STP_Design.ProgramParameters.C.GenConfFileIsCreated)
return true;
else
return false;
case STP_Data.Data.GenEncKeyControl:
if (STP_Design.ProgramParameters.C.GenEncKeyControlIsCreated)
return true;
else
return false;
case STP_Data.Data.AdvancedMenu:
return true;
case STP_Data.Data.MenuControl:
if (STP_Design.ProgramParameters.C.MenuControlIsCreated)
return true;
else
return false;
default:
return false;
}
}
Summery of what I am looking for:
I am having a main form where display different user controlls in. I am trying to create a seperate class which is accessable from each control/form in my project. This class should manage the controls which are shown. In the code above I illustrated how I tried to do this, but this does not result in the expected result.
Ok, Now I understand the context needed. We actually do something very similar in my program. Here is a basic outline of how we do it...
Layout
On the main form we have a Panel container that we call pnlMain. It is this control that we add and remove active user controls from. We also have a UserControl object at a global level on the form representing curActiveControl.
Code
When the user selects a window via one of the menu's, we run a function that looks like this
switch (UserSelection)
{
case "Page 1":
if(curActiveControl.GetType() != typeOf(Page1Control))
{
pnlMain.Controls.Remove(curActiveControl);
curActiveControl = new Page1Control();
//do setup and configuration things
pnlMain.Controls.Add(curActiveControl);
}
//do some post processing things
break;
//other pages/specific page controls
}
Refresh();
The downside to this specific method is that the pages themselves are not persistent, so if there are entries or variables you want to have active across a session rather than only while on a page, you have to store them in some other global object and reload them from the user control's Load or Constructor methods.
You could do this same thing but instead of creating a new control instance each time for curActiveControl you could simply replace it with the standby instance of the new control. Be careful with referencing and overwriting though, its not something I personally have tried before.
The key in the method we use is the Panel that holds the user controls. Rather than adjusting the visibility and Z-Order of a large number of user controls, we simply change the displayed control in the main panel and the other control don't even exist at any given point in time.
The other wrinkle is that this functionality is directly on our Main Form. I Don't know how well this will work as another partial class. Its definitely worth a try though.