Change Buttons to visible after a User logs in - c#

I made an SQL database with a connection and a table with user and password. I managed to create a login following a guide. The code is working fine to login, but what I want to do is to show all other Buttons on the main Form after a user logs in.
I am using a Panel in the main Form to show the second Form. Clicking Buttons show a UserControl in the middle Panel.
I just want to update the Button.Visible value from false to true without opening a new main Form.
I can make the Buttons visible when the Form loads but not when I try to set a condition. I can't figure out how to set a condition that when a user logs in successfully, the other Buttons are set to visible and the login Button is hidden.
Part of code in the MainLogin UserControl.
The MainMenu.UserAutherised I added was to pass the userID from a TextBox to the UserAutherised() method in the MainMenu Form when the login is successful.
if (mread.Read() == true)
{
MessageBox.Show("Login successfull");
this.Hide();
MainMenu.UserAutherised(text_userID.Text);
}
Part of code in MainMenu: I did this trying to solve the problem.
I thought that setting a bool to true when a user successfully logs in, I could have then called the ShowButtons() method to set Buttons to visible:
public static bool UserAutherised(string user)
{
bool returnValue;
string _user ="true";
string _noUser ="false";
bool _userID = bool.Parse(_user);
bool _noUserID = bool.Parse(_noUser);
}
if (user == "")
{
returnValue = _noUserID;
return returnValue;
}
else
{
returnValue = _userID;
return returnValue;
}
I get the bool value as far as I can understand from debugging, but when I try to use the if statement in the ShowButtons() method, I can't figure out how to get the bool value from UserAutherised() to if(UserAutherised()) to show the Buttons when the value is true.
I hope I described the problem well enough.
EDIT 1:
I tried the same event Action syntax to get the position and access for the user logging in. In the MainLogin form i added the following:
public event Action<string> ACCESS;
public event Action<string> POSITION;
string userAccess, userPosition;
and then i added the following in the mread.Read if-statement:
Sqlcommand cmd_get_position_Access = new SqlCommand (
"SELECT, Access FROM Users WHERE position = #position AND Access = #Access", dataconnection);
SqlParameter _position = new SqlParameter("#position",
SqlDbType.NVarchar);
SqlParameter _access = new SqlParameter("#Access", SqlDbType.NChar);
cmd.Parameters.Add(_position);
cmd.Parameters.Add(_access);
userPosition = mread["position"].ToString();
userAccess = mread["Access"].ToString();
I get a NullReferenceException when trying to Invoke the new events so i added the following if-else statement to fix it:
if (ACCESS == null || POSITION == null)
{
return;
}
else
{
ACCESS.Invoke(userAccess);
POSITION.Invoke(userPosition);
}
In the MainMenu button click event:
var userLogin = new MainLogin();
panel_Main.controls.Add(userLogin);
userLogin.userLogged += UserLogged;
userLogin.ACCESS += UserAccess;
userlogin.POSITION += Position;
userLogin.Show();
When debugging i can see that i get the Access value from database table. But when i try to use a method with if-statements but the conditions are skipped even when true. I also tried the switch-statement but same thing happens to cases. They are skipped. For example if admin login i get access yellow but case is skipped. Same thing happens to the if-statements conditions. Access is yellow and condition is true but if-statement is skipped. Why are they skipped when conditions are true?
private void UserAccess(string access)
{
switch (access)
{
case: "yellow":
userAdmin();
break;
case: "green":
userGreen();
break;
default:
break;
}
}
EDIT 2:
I found the problem. It turns out to be in the User table. Access was set to nchar data type which add spaces to the value. Access was getting the string "yellow ". I changed data type to varchar and it solved the issue.

Why are you using static method to access MainMenu?
I think it would be better to declare event in MainLogin form like:
public event Action<string> userLogged;
and invoke it after this.hide:
userLogged.Invoke(text_userID.Text);
And in MainMenu form create a handler for this event:
void UserLogged(string user)
{
if (user != "")ShowButtons();
}
And subscribe to userLigged event before showing MainLogin form like:
MainLogin loginForm = new MainLogin();
loginForm.userLigged += UserLogged;
loginForm.Show();

Related

How to stop Windows Form program execution until text box input is given?

I'm building a windows form application that stores employee information records in a database, including SSN. Next to the textbox where the SSN is input is requested, I have a checkbox that when clicked, shows me the full SSN instead of the last four digits. To ensure that only an administrator is accessing this information, I created a prompt form connected to a MS SQL DB that stores an admin password and would like to ask the user for a password for security purposes. Also, i'd like to be able to call this form whenever needed. I successfully implemented it but would like to add a feature that allows for 3 tries. Is there a way to stop the program execution and keep prompting the user for input in a textBox?
output is a variable that stores the result of the 'SELECT' query that gets the password.
confirmation is the Accept Button.
The only option i could think of forcing input was calling a new form. Only problem is, this code is inside the form and my gut tells me that's not the answer to this problem. I must be missing something.
confirmation.Click += (sender, e) => {
//If Password is correct.
if (textBox.Text == output)
{
isCorrect = true;
Pprompt.Close();
}
else
{
isCorrect = false;
//While the password is incorrect.
while (isCorrect == false)
{
//textBox.Text = "";
if (textBox.Text == output)
{
isCorrect = true;
Pprompt.Close();
break;
}
tryCount++;
if (tryCount == 3)
{
MessageBox.Show("Access Denied.");
break;
}
}
}
}
What I'd like to happen is for the form to keep asking me for input until the try limit is exceeded.
You cannot have the loop inside the click handler, because the UI freezes while it is running and the user does not get the opportunity make any entries.
Process only one entry and process the next when the user clicks the button again.
confirmation.Click += (sender, e) => {
if (textBox.Text == output) // Password is correct.
{
isCorrect = true;
Pprompt.Close();
}
else
{
isCorrect = false;
textBox.Text = "";
tryCount++;
if (tryCount == 3)
{
MessageBox.Show("Access Denied.");
Pprompt.Close();
}
}
}
Unless you are using multi-threading or async/await, the following is true:
Winforms is event based. I.e., if no event handler is running, no code is running.
If code (i.e. an event handler) is running, the user interface (UI) is frozen and the user cannot make any input. He cannot enter text or click any buttons, cannot scroll lists and cannot resize or move the window.
While an event handler is running, no other event handler will ever be called. I.e., an event handler will never be interrupted by another one. This prevents you from having to deal with multi-threading issues unless you are using multi-threading explicitly.
If an event should be fired (e.g. a timer tick) while an event handler (e.g. a button click handler) is running, the execution of the event handler associated to this new event will be deferred until after the first event handler returns.

c#- Display error message if there is no issue permission

I have a program in c# that allow users to issue events ( think of it like different vouchers from different category). In the program, there is a function called promotion permission to set access to the event. The two access are view permission and issue permission. View permission allow user to view the event and issue permission allow user to issue (print) out the event. For example, if the event is set to as view permission: yes and issue permission : no , then user cannot issue the event but could view it. If both cases are yes then user may issue the event.
Now I have another function in program to issue the event(voucher). In that program, it shows a list of events (when user enter their id) and are able to tick(checkbox) the event they wish to issue. What I need is if the event does not have issue permission but view permission, it should not allowed user to tick the checkbox and if they try to do so, it should throw a error message informing user of the restriction.
This is my code:
private void lisVieBenefits_ItemChecked(object sender, ItemCheckedEventArgs e)
{
RestartAutoLogoffTimer();
DataSet dsData = oBSPromoPermission.GetBrowseData();
if (e.Item.Checked && !IsEnoughtToRedeemPointEarnReward())
{
// Uncheck previous item
e.Item.Checked = false;
return;
}
if (panBenefitSelection.Enabled)
{
int intTotal = 0;
for (int intCounter = 0; intCounter < lisVieBenefits.Items.Count; intCounter++)
{
if (lisVieBenefits.Items[0].ListView.Items[intCounter].Checked)
intTotal += 1;
}
if (intTotal > intMaxBenefitSelection)
{
lisVieBenefits.Items[0].ListView.Items[e.Item.Index].Checked = false;
SetErrorHint("Please select not more than (" + intMaxBenefitSelection + ") benefit selection");
}
if (dsData.Tables[0].Columns[3].ToString() == "True" && dsData.Tables[0].Columns[4].ToString() == "False")
{
// lisVieBenefits.Items[0].ListView.Items[e.Item.Index].Checked = false;
SetErrorHint("This event does not have an issue permission");
}
}
I declared and call the class:
private BSPromoPermission oBSPromoPermission = new BSPromoPermission();
So,dsData is a dataset variable declared to call the database that have view permission and issue permission. As shown in the code, column[3] is set to true for view permission and column[4] is set to false for issue permission.
Somehow this isn't working. Any help would be appreciated.

Custom Message Box displays after Message box

I have some code that when I call my CustomMessageBox it displays the box with a user prompt for an amount of my object to add, once that is done I have it added to a list of objects. Once added, it then Displays a MessageBox.Show to just let the user know it was added.
My problem is that when I run the code it executes all the code, bypasses the display of the Custom message box, then displays the MessageBox.Show, and THEN displays the CMB.Show. I ran the code through the debugger and followed the trail and it hits the CMB.Show before the MessageBox.Show, but is displayed once the code is done. Sorry, I am still learning and might not be telling the problem well, please let me know if there is anything I can further explain upon.
Some code:
private int BasicLand(Card basicLand)
{
var countBox = new TextBox
{
Name = "count",
Width = 100,
};
var cmbCount = new CustomMessageBox
{
Caption = "Blah",
Content = countBox,
RightButtonContent = "ok",
};
cmbCount.Dismissed += (s1, e1) =>
{
switch (e1.Result)
{
case CustomMessageBoxResult.RightButton:
if (int.TryParse(countBox.Text, out tempInt) && Convert.ToInt32(countBox.Text) > 0)
{
countReturn = Convert.ToInt32(tempInt);
break;
}
else
{
//Some code for error....
}
}
};
cmbCount.Show();
return countReturn;
}
Then the other part that triggers first but is last in the code block.
MessageBox.Show("Object was added to List!");
I tried adding the ShowDialog to the custom box but it came up broken in VS. BasicLand is called within another method and when the object is added to the list it will display the MessageBox.Show.
The problem with your code is, it does not take into account that any user interaction is asynchronous. When you call Show() it will actually show the messagebox, but it will not block your currently running thread, the other statements after the call to Show() will be executed immediately and thus your method returns a returnvalue that has not been provided by the user but is just the default. To fix this you have to write your code in continuations.
private void PromtUserForFeeblefezerAmount(Action<int> continueFeeblefzing, Action cancel)
{
var messagebox = CreateFeeblefezerPromt();
messagebox.Dismissed += (sender, args) =>
{
if ( args.Result == CustomMessageBoxResult.RightButton )
continueFeeblefzing( GetFeeblefezerAmount(messagebox) );
else
cancel();
};
messagebox.Show();
}

Context.Items clears during page refresh/transfer

I am working on a class project and I've run into a problem I can't figure out. I have a feeling it's actually pretty easy, but I've been working on stuff so long I can't think straight anymore.
I have a login page that allows a user to login and pass 2 data items to the next page using Context.Items and Server.Transfer. Here is the code snippet:
Context.Items["preferred"] = true;
Context.Items["pageNum"] = 1;
Server.Transfer("ProductsShelf.aspx");
On the "ProductsShelf" page I can access those two items and use the data like so:
pageNumber = (int)Context.Items["pageNum"];
I am then using a switch-statement with pageNumber to display certain information:
switch (pageNumber)
{
case 1:
imgProd.ImageUrl = "assets/laptop.bmp";
lbl_Name.Text = "Laptop";
lbl_desc.Text = "This is a cheap laptop!";
lbl_price.Text = "199.99";
break;
}
Obviously there's other entries I'm omitting. What I want to do is click a next or previous button and use the event to change the Context.Items["pageNum"] data so the Page_Load() event uses different data in the switch-statement. Hope that makes sense. Here is one of the button click events:
protected void btn_Prev_Click(object sender, EventArgs e)
{
if (pageNumber == 1 || pageNumber == 2)
{
Context.Items["pageNum"] = 1;
}
else if (pageNumber == 3)
{
Context.Items["pageNum"] = 2;
}
Context.Items["preferred"] = preferredCustomer;
Server.Transfer("ProductsShelf.aspx");
}
The problem is that before the button click event fires, the form posts and clears the Context.Items and pageNumber values. This means that the button event if-statements never fire and it results in:
pageNumber = (int)Context.Items["pageNum"];
Being null, throwing an exception and making me very sad. So my question is, how can I go about retaining the values? Should I switch to Response.Redirect and have something like ?page=1 in the URL? Or will that clear too when the form posts? Hopefully I'm not doing this completely wrong.
If TL;DR, here's a quick summary:
Context.Items has 2 values passed with Server.Transfer
These values determine what's shown on the next page
The form clears Context.Items and variables before button click event fires
The values are null, the if-statement doesn't run, and the app throws an exception
Question: how should I go about retaining those values?
Thanks a lot. :)
HttpContext items can be used within one request only - it will be recreated for next request so your values are bound to lose. You should use view-state to preserve data across post-backs. In page load, you should check if data exists in context and then copy it to view-state. Then in button click events, you can read the data from view-state, put into the context items and do server.transfer.
Here's simple sample code:
private int PageNumber
{
get
{
var value = ViewState["pageNum"];
return null == value? 1: (int)value;
}
set
{
ViewState["pageNum"] = value;
}
}
private bool IsPreferredCustomer
{
get
{
var value = ViewState["preferred"];
return null == value? false: (bool)value;
}
set
{
ViewState["preferred"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
var preferred = Context.Items["preferred"];
if (null != preferred)
{
IsPreferredCustomer = (bool)preferred;
}
var pageNum = Context.Items["pageNum"];
if (null != pageNum )
{
PageNumber = (int)Context.Items["pageNum "];
}
}
Use the same PageNumber property in event code.

How to use error provider at run time along with associating any control to validate

I am trying to create a Validation in a reusable fashion.
Purpose:
Make the validation control reusable.
Error Provider should associate with control passed dynamically and can be set or cleared at run time.
When user press OnClick event then all the controls gets validated with their own Error Providers.
public bool IsFieldEmpty(ref TextBox txtControl, Boolean SetErrorProvider,string msgToShowOnError)
{
ErrorProvider EP = new ErrorProvider();
if (txtControl.Text == string.Empty)
{
if(SetErrorProvider==true)
EP.SetError(txtControl, msgToShowOnError);
return true;
}
else
{
if(SetErrorProvider==true)
EP.Clear();
return false;
}
}
Issue:
Every time the function is called new errorprovider object gets created which i dont want.
Every control should not have more than 1 error provider and i should be able to search it just like as done in asp.net to search for some control on a Page.
How can I do this
In most cases you really only need one instance of ErrorProvider on a form.
E.g.
ErrorProvider errorProvider1 = new ErrorProvider();
or just drag one from the toolbox onto the form.
When calling an ErrorProvider, you supply the control and the message,,
errorProvider1.SetError (dateTimePicker1, "HEY BAD DATE");
To clear the error...
errorProvider1.SetError (dateTimePicker1, "");
So, one ErrorProvider instance is all you really need in most situations.
Make on PropertyOnDemand like this and access that property every time u need new ErrorProvider
private ErrorProvider _ErrorProvider = null;
//PropertyOnDemand
private ErrorProvider ErrorProviders
{
get
{
if (_ErrorProvider == null)
{
_ErrorProvider = new ErrorProvider();
return _ErrorProvider;
}
else
return _ErrorProvider;
}
}
public bool IsFieldEmpty(ref TextBox txtControl, Boolean SetErrorProvider, string msgToShowOnError)
{
if (txtControl.Text == string.Empty)
{
if (SetErrorProvider == true)
ErrorProviders.SetError(txtControl, msgToShowOnError);
return true;
}
else
{
if (SetErrorProvider == true)
ErrorProviders.Clear();
return false;
}
}

Categories

Resources