I'm working on a new button that resets the form application when clicked.
However I've run into a problem that I can't seem to solve.
Basically what I want to do is to clear the list boxes when the the button new is clicked.
The New button should initialize the program exactly as at
start-up (but without restarting the application). If data has not
been saved, allow the user (through a MessageBox) to confirm
proceeding without saving current data or go back to the current
session.
Here is how I tried it:
private void mnuNew_Click(object sender, EventArgs e)
{
for (int index = 0; index < animalmgr.Count; index++)
{
Animal animal = animalmgr.GetAt(index);
if (animal != null)
{
// error message
DialogResult dialogResult = MessageBox.Show("The data will be lost. Continue?", "Are you sure?", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
InitializeGUI();
}
else if (dialogResult == DialogResult.No)
{
}
}
else
{
ClearLists(); <--------This does not work!
}
}
}
private void InitializeGUI()
{
animalmgr.DeleteAll();
Resultlst.Items.Clear();
foodItemslst.Items.Clear();
}
public void ClearLists()
{
Gendercmb.DataSource = Enum.GetValues(typeof(GenderType));
Categorylst.DataSource = Enum.GetValues(typeof(Categorytype));
Resultlst.Items.Clear();
foodItemslst.Items.Clear();
}
What does work: It does display a messagebox if the animal object is not null.
What does NOT work: When I load a file and display the object on the listbox, the new button does NOT clear the list. The reason is because the animal object is null after loading a file and displaying, but it should call the else and clear the list, but it doesn't.
UPDATE:
The problem is NOT the the ClearLists() method. The problem is that the if statement, never seem to reach down to call it. The problem is not the ClearLists() method itself. The problem is that it never is called.
I believe the problem lies in your logic comparison of
animal != null
Look at your logic, the line above gives animal a value, even if that value is 0. Therefore animal is never null, because it always has a value.
Try this.
public void ClearLists()
{
Gendercmb.DataSource = Enum.GetValues(typeof(GenderType));
Categorylst.DataSource = Enum.GetValues(typeof(Categorytype));
Resultlst.DataSource = new List<ListItem>();
foodItemslst.DataSource = new List<ListItem>();
}
Remember, if this is an asp.net webforms application, you also need to call DataBind() dunction on foodItemslst and Resultlst both.
Related
I have a DataGridView and the DataGridView's DataSource is a BindingList I got from the Entity Framework (V6) via context.Person.Local.ToBindingList().
After I set the DataSource to this BindingList, I dispose the context, because I read that keeping the context open would be bad practice.
So, if I wanted to add a new row, I would click on the "add" button that comes with the BindingNavigator that got created when I dragged the "people" object data source to my Windows Form.
Every time I click the "add" button, I get an exception that tells me that the context has been disposed.
Do I need to keep the context open all the time when using DataGridView? Oh and: the DataSource might change during runtime depending on the selection of a ListBox Item.
Also, when the context has been disposed and I edited one row from the DataGridView, how could I find out (after multiple changes) which row has changed?
I tried to do:
foreach(DataGridViewRow row in peopleDataGridView.Rows)
{
People item = (People)row.DataBoundItem;
if (item != null)
{
db.People.Attach(item);
}
}
db.SaveChanges();
...but SaveChanges() did not recognize any changes. However, if I force every attached item to a "modified" state, it works. But I do not want to change 100 items to "modified", if only one got actually modified.
Any ideas?
EDIT 1
Oh well, so I changed my code to keep the context open all the time (or at least as long as the form gets displayed).
Now, I ran into a different problem (people may have many jobs):
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
//jobBindingSource.Clear(); this caused another error at runtime...
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
The DataGridView that is bound to this jobBindingSource instance shows the correct jobs for a person, but in addition to the jobs from the previously selected person. I tried to Clear() the entries, but if I do this and click on the same person twice, the datagridview starts to sometimes show no entries at all. A strange behaviour.
What am I doing wrong now?
EDIT 2
Okay... I found a solution myself. But I refuse to accept that this is the correct way to do it:
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
db.Dispose();
db = new PeopleJobsEntities();
db.People.Attach(p);
db.Entry(p).Collection(person => person.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
Only if I dispose the context and open it anew, the whole thing works. The reason is that if I clear the local cache (of db.Job.Local), its entries will not be reloaded again even if I use the Load() method. Is there some way to force the reloading of entities?
While I try not to keep the DBContext open for a long period of time, with datagrids you don't have much choice. I set my grid's DataSource property to IQueryable<T> and then all the edits, deletes and additions are taken care of by the grid and context itself. You just have to call dbContext.SubmitChanges() whenever you want to persist the changes. You can save each time a user leaves a row by saving on the RowLeave or the RowValidated event. Or you can save when you close the form. But also make sure you call dbContext.Dispose() when you close the form as well.
To find out which rows change you can view the ChangeSet that is returned by doing the following:
var changes = dbContext.GetChangeSet();
dbContext.SubmitChanges();
Be sure if your item is not null.
Check your connection string.
And, try this :
db.People.Add(item);
Instead of :
db.People.Attach(item);
Ok, thanks to #jaredbaszler I came up with this solution that works fine for me.
I decided to keep the DbContext alive all the time. To clear the local cache, I detached every entity inside in a loop. I think this is a very disgusting way to do it. There must be a better way...
This is what I have:
PeopleJobsEntities db;
public FormTest()
{
InitializeComponent();
db = new PeopleJobsEntities();
db.Database.Log = Console.Write;
db.People.Load();
List<People> peoplelist = db.People.Local.ToList();
listBox1.DataSource = peoplelist;
}
private void FormTest_FormClosing(object sender, FormClosingEventArgs e)
{
if (db != null)
db.Dispose();
}
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
List<Job> oldlist = db.Job.Local.ToList();
foreach (Job j in oldlist)
{
db.Entry(j).State = EntityState.Detached;
}
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
private void jobBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
foreach(DataGridViewRow row in jobDataGridView.Rows)
{
if(row != null && row.DataBoundItem != null)
{
Job j = (Job)row.DataBoundItem;
if(db.Entry(j).State == EntityState.Added)
{
if(j.People.Count == 0)
{
People people = (People)listBox1.SelectedItem;
if (people != null)
j.People.Add(people);
}
}
}
}
db.SaveChanges();
}
Editing entries works
Adding new entries works
Deleting entries works
Okay, so please don't flame me too much, this is my 1st question here, and maybe what I am trying to do is not even possible. Obviously I am not an expert; that's why I am coming to you. :)
I have searched all over here, MSDN, and the rest of the internet (most of which points back here) without any luck. I did see one question asking about using the OpenFileDialog to select a folder instead of a file. I am almost certain that I have seen this in mainstream applications, but the question was marked as being too vague, and that particular caveat was unaddressed in the responses.
I have some text boxes that need file/folder paths. I want to simplify the two methods that handle this, into one. The only difference, is that once selects a file, and the other selects a folder. For simplicity and readability, I'd like to consolidate them.
Is this possible, without literally putting the contents of each code method into a big IF ?
Here are the two methods:
private void FolderBrowser(object sender, EventArgs e)
{
TextBox SenderBox = sender as TextBox;
if (SenderBox.Text != "")//if the text box is not empty
{
//set the selected path to the text box's current contents (incase of accidental entry)
FileBrowserDialog.FileName = SenderBox.Text;
}
if (FileBrowserDialog.ShowDialog() == DialogResult.OK)
{
SenderBox.Text = FileBrowserDialog.FileName;
}
}
private void FileBrowser(object sender, EventArgs e)
{ //basically the same as the folder browser above, but for selecting specific files
TextBox SenderBox = sender as TextBox;
if (SenderBox.Text != "")//if the text box is not empty
{
//set the selected path to the text box's current contents (incase of accidental entry)
FileBrowserDialog.FileName = SenderBox.Text;
}
if (FileBrowserDialog.ShowDialog() == DialogResult.OK)
{
SenderBox.Text = FileBrowserDialog.FileName;
}
}
I have added a Tag to each TextBox, indicating if it needs a file or a folder. I'd like to use the Tag as the condition by which I determine if I should be using a file or folder browser. This is where my ignorance shows; I had envisioned something like this NONWORKING code:
private void browser(object sender, EventArgs e)
{
//cast sender as a textbox
TextBox tBox = (TextBox)sender;
object browser = null;
if (tBox.Tag.ToString().Equals("Folder"))
{
browser = new FolderBrowserDialog();
}
else
{
browser = new OpenFileDialog();
}
if (tBox.Text != "")//if the text box is not empty
{
//set the selected path to the text box's current contents (incase of accidental entry)
browser.FileName = tBox.Text;
}
if (browser.ShowDialog() == DialogResult.OK)
{
tBox.Text = browser.FileName;
}
}
Am I crazy, or is there a way to accomplish what I have in mind? To be clear, I want to know if there is:
An existing Object/Method that would allow for the selection of a file or a folder, or
A way to dynamically re-define an object as a different type of object
Any other way to use 1 Method to dynamically allow for the use of OpenFileDialog or FileBrowserDialog based on some Tag defined on the calling object.
This is the easiest way I've found of solving this problem without relying on third party code, but you'll need to add some sanity checks, in case the user goofs around with the input:
OpenFileDialog ofd = new OpenFileDialog();
ofd.CheckFileExists = false;
string defaultFilename = "Select this folder";
ofd.FileName = defaultFilename;
if (ofd.ShowDialog().Value)
{
// Check if the user picked a file or a directory, for example:
if (!ofd.FileName.Contains(defaultFilename))
{
// File code
}
else // You should probably turn this into an else if instead
{
// Directory code
}
// Alternatively, but still as unsafe
if (File.Exists(ofd.FileName))
{
// File code
}
else
{
// Directory code
}
}
Basically, the "trick" here is to set OpenFileDialog's CheckFileExists to false.
Try using FolderBrowserDialogEx.
See detailed answers here:
How do you configure an OpenFileDialog to select folders?
Both dialogs (FileOpenDialog and FolderBrowserDialog) inherit from CommonDialog; however, this base class has no property to retrieve the result. Moreover, the property is named differently in both dialogs.
You can solve the problem by creating a wrapper. Inheritance is the proper way of re-defining an object as different type.
public abstract class FileFolderDialogBase
{
public abstract bool ShowDialog();
public string Result { get; protected set; }
}
public class FileDialog : FileFolderDialogBase
{
public override bool ShowDialog()
{
var ofd = new OpenFileDialog();
if ofd.ShowDialog() == DialogResult.OK) {
Result = ofd.FileName;
return true;
}
return false;
}
}
public class FolderDialog : FileFolderDialogBase
{
public override bool ShowDialog()
{
var fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
Result = fbd.SelectedPath;
return true;
}
return false;
}
}
Usage:
var dialog = textBox.Tag == "Folder" ? new FolderDialog() : new FileDialog;
if (dialog.ShowDialog()) {
textBox.Text = dialog.Result;
}
You can push it further by creating a factory class
public static class FileFolderDialog
{
public static FileFolderDialogBase Create(string type)
{
swich (type.ToLowerInvariant()) {
case "folder":
case "dir":
case "directory":
return new FolderDialog();
default:
return new FileDialog();
}
}
}
Usage
var dialog = FileFolderDialog.Create(textBox.Tag);
if (dialog.ShowDialog()) {
textBox.Text = dialog.Result;
}
why you not try extending the TextBox Class?
It's easy and reusable and you only need to drag and drop your custom control to the WinForm
class FileTextBox : System.Windows.Form.TextBox{
//===>This enumeration is more readable insted of a string XD
public enum DialogType{
File,Folder
}
//===>This property we will handle what kind of Dialog to show
public DialogType OpenDialogType{
get;
set;
}
//===>This is where Object Oriented Programming a& Design do his magic
public System.Windows.Forms.DialogResult ShowDialog(string Title =""){
//===>This function is where we define what kind of dialog to show
System.Windows.Forms.DialogResult Result = System.Windows.Forms.DialogResult.None ;
object Browser=null;
switch(this.OpenDialogType){
case DialogType.File:
Browser = new OpenFileDialog();
((Browser)OpenFileDialog).Title= Title;
if(this.Text.Trim() !="" && this.Text != null ){
((Browser)OpenFileDialog).FileName = this.Tex;
}
Result = ((Browser)OpenFileDialog).ShowDialog();
break;
case DialogType.Folder:
Browser = new FolderBrowserDialog ();
((Browser)FolderBrowserDialog).Description = Title;
if(this.Text.Trim() !="" && this.Text != null ){
((Browser)FolderBrowserDialog).RootFolder = this.Text;
}
Result = ((Browser)FolderBrowserDialog).ShowDialog();
break;
}
return Result;//===>We return thi dialog result just if we want to do something else
}
}
/*
Create a class and copy/paste this code, I think is going to work because
I didn't compiled then go to ToolBox window find this control and Drag & Drop
to your WinForm and in the property window find OpenDialogType property
and this is where you kind define the behavior of OpenDialog();
I'm currently working in a little project in Vs where I create a custom
UI Control downloaded from my git repository
https://github.com/MrAlex6204/GYMSystem
*/
I have a modeless UI that adds a userID to a list that allows or removes access to parts of a program. When I click the modify button everything works as it should. Suppose I close the dialog and realize "Wait, forgot to do X". When I reopen the dialog box, perform my work and click Modify, the value for adding the userID is still available to the program even though the textbox is blank.
It's happening somewhere in the following code.
public static void checkSame()
{
int count = 0;
bool test = false;
while (linesPerm.Length >= count && tbPermValue != "")
{
if (linesPerm.Length >= count)
{
test = linesPerm.Contains(tbPermValue);
count += (linesPerm.Length + 1);
if (test == true)
{
DialogResult dr = MessageBox.Show("The UserID " + tbPermValue +
" already exists in the Permissions column. "
+ Environment.NewLine + "Would you like to add the UserID" +
tbPermValue + " to the Permissions column anyway?",
"User Already Exists", MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
switch (dr)
{
case DialogResult.Yes:
break;
case DialogResult.No:
tbPermValue = "";
break;
}
}
}
else
{
MessageBox.Show("Do Nothing");
}
}
}
If the user selects No on the dialog box, the value of tbPermValue is not available to the program. If the user selects Yes then the value of tbPermValue persists even if the dialog box is closed and reopened. I have tried to clear the textbox value like so.
tbUserName.Text = "";
tbUserName.Clear();
and several other ways. tbUserName value is being cleared from the textbox, but not from the code above. I get the value of tbPermValue like this.
public static void addPerm(System.Windows.Forms.Form targetForm)
{
foreach (Control C in targetForm.Controls)
{
if (C.GetType() == typeof(TextBox))
{
if (C.Text != "")
{
tbPermValue = C.Text;
}
}
}
}
This is a modeless dialog box owned by it's parent.
Can anyone point me in a direction that would remove access to tbPermValue to the DialogResult portion of the first code box after the button is clicked. I can't lose it completely because tbPermValue is used in other code down the line.
EDIT: Ok. I just tested this and the value is being held in memory. I have a dialog Form1 that has a button that opens dialog StartHere. On StartHere there is a button that opens Permissions. StartHere owns Permissions so that when I close StartHere, Permissions and all other child forms of StartHere will close. These are all modeless dialogs. My variable tbPermValue is being held in memory way back to Form1. The value is not being disposed when I close the dialog StartHere. I'm going to go back and research Garbage Collection at the advice of Eric below. Thank you Eric. I'll delete the question or at least post a new better question once I find out the rules for this process. Thank You.
Edit 2: Here is the code you asked for γηράσκωδ'αείπολλάδιδασκόμε
private void bModify_Click(object sender, EventArgs e)
{
WidgetLogic.addPerm(this);
WidgetLogic.checkSame();
WidgetLogic.writePerm(this);
WidgetLogic.writeAdmin(this);
WidgetLogic.writeDetailer(this);
tbUserName.Clear();
}
As noted above I have tried numerous ways to clear tbUserName to no avail.
Don't use tbPermValue but instead use the textbox directly:
while (linesPerm.Length >= count && tbUserName.Text != "")
EDIT
Change the code in addPerm to this, and you are done :):
public static void addPerm(System.Windows.Forms.Form targetForm)
{
foreach (Control C in targetForm.Controls)
{
if (C.GetType() == typeof(TextBox))
{
tbPermValue = C.Text;
}
}
}
You don't need the switch (dr) in checkSame()
I see that you say you have tried setting the following in the "yes" part of your switch statement:
tbUserName.Text = "";
tbUserName.Clear();
But in your "no" part, you don't set tbUserName, but instead you set the variable tbPermValue. From what I can tell, you should also be setting
tbPermValue = "";
in your "yes" part as well to clear that variable, or even just move it out of the switch and have it do that before the dialog closes since you would be setting it in all of the possible switch cases anyways.
I have the following snippet of code that allows me to pull the properties from an object in my list and assign them to variables in other forms. However, I need to be able to pull the data from my variables in the other form and use those to set the properties of the given object.
My class Account is used to populate my list accounts. On my next form AccountMenu I have a class Variables1 that contains accessible variables that are used throughout the rest of my forms to keep track of the checking balance and saving balance. When logging off from the AccountMenu, I want to be able to pass the values from Variables1 to the account that was initially used.
I know how to pass variables from one form to another, but I'm not really sure how to update the form automatically, without a button, on the original form. Thus, the solution that I see is that I have a button on my AccountMenu form that "logs" the user out, via this.close(); Additionally, I guessed that under that button, I need to have some code that assigns the variables as properties to the object. I'm just not sure how I can access the set properties of the object, since it is dynamically called with the code below.
Can someone help me figure out what I need to do? Below is some of the relevant code so that you can see how I have things set up. I am just not sure how to access "matches" from the other form in order to update that specific object properties. Thank you, anyone, who can help!
//variable that will be used to check textbox1.Text
string stringToCheck;
//array of class Account
List<Account> accounts = new List<Account>();
public MainMenu()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//set value to user's input
stringToCheck = textBox1.Text;
//set a var that only returns a value if the .Name already exists
var matches = accounts.FirstOrDefault(p => p.Name == stringToCheck);
//check through each element of the array
if (matches == null)
{
accounts.Add(new Account(stringToCheck));
textBox1.Text = "";
label3.Visible = true;
}
else if (matches != null)
{
//set variables in another form. not sure if these are working
Variables1.selectedAccount = matches.Name;
//is this calling the CheckBalance of the instance?
Variables1.selectedCheckBalance = matches.CheckBalance;
//same thing?
Variables1.selectedSaveBalance = matches.SaveBalance;
//switch to form
AccountMenu acctMenu = new AccountMenu();
this.Hide();
acctMenu.Show();
}
}
As per my understanding I think what you required is kind of trigger on your parent form that needs to be called from your child application.
If that is what you required than you can go with defining an event on your AccountMenu form. and register this event from your Accounts form.
Than simply raise this event from your AccountMenu subform.
Deletegates and Events are really works like magic :)
Let me show you some code how to do this.
Code required in AccountMenu window:
public delegate void PassDataToAccounts(string result);
public event PassDataToAccounts OnPassDataToAccount;
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (OnPassDataToAccount != null)
OnPassDataToAccount("result");
base.OnClosing(e);
}
Code required in Accounts window button1_Click event where the AccountMenu will open:
//set variables in another form. not sure if these are working
Variables1.selectedAccount = matches.Name;
//is this calling the CheckBalance of the instance?
Variables1.selectedCheckBalance = matches.CheckBalance;
//same thing?
Variables1.selectedSaveBalance = matches.SaveBalance;
//switch to form
AccountMenu acctMenu = new AccountMenu();
acctMenu..OnPassDataToAccount += childwindow_OnPassDataToAccount;
this.Hide();
acctMenu.Show();
}
void childwindow_OnPassDataToAccount(string result)
{
if (result == "result")
{
// Processing required on your parent window can be caried out here
//Variables1 can be processed directly here.
}
}
Im currently facing the problem that when i try to set focus on some control (textBox), nothing happens, maybe i just overlooked something.(somewhere i found that focus is "low-level" method and that select() should be used instead, however, it doesnt work as well)
From form Login, i launch new instance of EncryptPSW form
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
EncryptPSW ePSW = new EncryptPSW();
ePSW.setOsLog(false, this);
ePSW.ShowDialog();
}
On Button(which is located on EncryptPSW form ) click event i call fill method
public void fill()
{
if (textBoxPSW.Text.Length == 8)//psw has to be 8 chars long
{
if (save)//determinating whether save or fetch of data should be done
{ login.launchSave(textBoxPSW.Text,this); }
else { login.launchOpen(textBoxPSW.Text,this); }
}
else { MessageBox.Show("The password must contain 8 characters");}
}
Which launches either save or open method from Login (my problem is just with open, since during save i dont need to do anything with Focus)
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
setFocus();
}
After all the work is done, setFocus() should be called in order to set focus and other properties.
public void setFocus()
{
textBoxDatabase.Focus();
textBoxDatabase.SelectionStart = textBoxDatabase.TextLength - 1;
textBoxDatabase.SelectionLength = 0;
}
I tried so many different ways, like:
Calling setFocus() from within EncryptPSW_FormClosed
Calling whole open process after the EncryptPSW is closed (from within EncryptPSW_FormClosed)
and many more, however i dont remember it all.
In the case of Form_Closed the weird thing is, that when i tried to show a message box from there instead of setting focus (just to see where the problem might be), it's showed before the EncryptPSW form is closed.
My only guess about this is that the instance of EncryptPSW is somehow blocking Login form and it's controls
I hoped i described my problem well enough and that it makes at least a bit of sense ;]
Thanks in advance,
Regards,
Releis
Since the textbox is in the login form, and you are opening the EcryptPWS from it as a dialog (child), your login form will not be able to set focus to anything. You will need to set focus after it is closed. You can do this:
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
using(EncryptPSW ePSW = new EncryptPSW())
{
ePSW.setOsLog(false, this);
if (ePSW.ShowDialog() == DialogResult.OK)
{
textBoxDatabase.Focus();
}
}
}
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.DialogResult = DialogResult.OK;
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
}
OK this maybe the ugliest thing I saw round this but.
using
public void setFocus()
{
textBoxDatabase.Focus();
textBoxDatabase.SelectionStart = textBoxDatabase.TextLength - 1;
textBoxDatabase.SelectionLength = 0;
}
Change your code at
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
setFocus();
}
to
delegate void settingfocus();
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
settingfocus sf = new settingfocus(setFocus);
this.BeginInvoke(sf);
}
This worked for me
(Sorry for apparently thinking insert "this" before procedure, and change line x to this was legable)