First of all, if I click a button the method cbBefüllen will execute.
private void btnEntfernen_Click(object sender, EventArgs e)
{
FeiertageEntfernen entfernen = new FeiertageEntfernen();
entfernen.cbBefüllen();
entfernen.Show();
entfernen.Focus();
}
The following method is just here as an interface between my form and a class. (Please don't ask, in my code I have some good reasons for it ;) ).
public void cbBefüllen()
{
database.cbFeiertagebefüllen();
}
The method cbFeiertagebefüllen (tries to) fills my ComboBox, which is located in the form "feiertagentfernen".
public void cbFeiertagebefüllen()
{
FeiertageEntfernen feiertagentfernen = new FeiertageEntfernen();
string Query = #"select bezeichnung from feiertage";
using (var command = new SQLiteCommand(Query, sqlite_conn))
{
if (sqlite_conn.State != ConnectionState.Open)
{
sqlite_conn.Open();
}
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
string übergabe = reader.GetString(0);
feiertagentfernen.cbFeiertag.Items.Add(übergabe);
}
}
}
}
But after this whole process my ComboBox is still empty. The reader in the last picture picks the correct value from the database, but somehow it won't write it into the ComboBox.
Your problem is in this line:
FeiertageEntfernen feiertagentfernen = new FeiertageEntfernen();
in your cbFeiertagebefüllen()
You make a new form but you want your combo box from the form from the 1st piece of code to be filled. To fix this you could pass along an instance of the form to the filling method.
The updated 2 pieces of code will be (first piece can be left alone):
In cbBefullen:
database.cbFeiertagebefüllen(this);
//'this' means we're passing along the form as parameter
In cbFeiertagebefüllen:
public void cbFeiertagebefüllen(FeiertageEntfernen feiertagentfernen)
{
string Query = #"select bezeichnung from feiertage";
using (var command = new SQLiteCommand(Query, sqlite_conn))
{
if (sqlite_conn.State != ConnectionState.Open)
{
sqlite_conn.Open();
}
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
string übergabe = reader.GetString(0);
feiertagentfernen.cbFeiertag.Items.Add(übergabe);
}
}
}
}
The FeiertageEntfernen form instance on which you're filling the cbFeiertag combo box in cbFeiertagebefüllen() is not the form's instance you're showing after that. You need to pass the entfernen instance to cbFeiertagebefüllen():
public void cbBefüllen()
{
database.cbFeiertagebefüllen(this);
}
public void cbFeiertagebefüllen(FeiertageEntfernen feiertagentfernen)
{
// Use the passed in instance instead of a newly created one
//FeiertageEntfernen feiertagentfernen = new FeiertageEntfernen();
string Query = #"select bezeichnung from feiertage";
// ....................
}
For this to work, the ComboBox which you need to fill, should be globally declared, i.e. outside the scope of your functions. The rest is probably fine. Also it's better if you get the values you need to display in the comboBox to the main form rather than calling the ComboBox instance 2 levels deeper.
I know this is a little confusing, in simple words, What you could do is, fill the values(descriptions of the holidays) from the DataBase into a list. Make your functions return this list when called. And finally where the ComboBox is declared, you could just add that list as the source of the ComboBox
It looks like you are adding the options to the combo box, but you are not actually setting the selected item.
To do so, you need to set cbFeiertag.SelectedIndex or cbFeiertag.SelectedValue.
Related
Hey guys new to C# and I am trying to setup a GUI, all I want the GUI to do is have a simple file explorer with a CheckedListBox to represent selected files.
I can get the CheckedListBox to show up and click on files but I'm not sure how to continue from here, most tutorials stop here, or go too advanced with tree view and other things that seem unnecessary for what I am trying to do.
Here is my code:
Any help is appreciated and if you guys could point me in the right direction that would be awesome.
EDIT:
To rephrase my question:
I want the user to select files through the CheckedListBox (user input stops here), and for those selected files to be put in a list that my code can manipulate.
Not sure how to accomplish this after my first foreach loop (which adds all files in the selected directory to the CheckedListBox for user selection).
The second foreach loop is an attempt at this, manipulating the files so that they output their filenames after being selected. However no Messagebox shows up and I assume that their is a disconnect between the user selecting files and the codes attempt at manipulating said files.
Second Edit:
I think I figured it out I made a second button and from here it looks like I can manipulate the chosen files however I want.
Currently the code is working the way I would expect it to work.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace SelectFiles
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
checkedListBox1.CheckOnClick = true;
}
private void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
MessageBox.Show(fbd.SelectedPath);
checkedListBox1.Items.Clear();
string[] files = Directory.GetFiles(fbd.SelectedPath);
foreach (string file in files)
{
checkedListBox1.Items.Add(file);
}
}
private void button2_Click_1(object sender, EventArgs e)
{
List<string> list_all_excelfiles = new List<string>();
foreach (string item in checkedListBox1.CheckedItems)
{
list_all_excelfiles.Add(item);
MessageBox.Show(Path.GetFileName(item));
}
}
}
}
First i advice you to assign Value member and Display member for each item.
Display Member will be visible to user
Value Member will we use in code
To do this first create simple custom class
public class Int_String
{
public int _int { get; set; }
public string _string { get; set; }
}
Be careful because get; set; part is important to be there since if not code will not work
Now what you need to do is create list of items with custom class like this
class YourForm : Form
{
List<Int_String> myList = new List<Int_String>(); //Create list of our custom class
public YourForm()
{
PopulateMyList();
}
private void PopulateMyList()
{
//Here read from database or get data somehow and populate our list like this
//I will populate it manually but you do it in foreach loop
myList.Add(new Int_String { _int = 0, _string = "First Item" });
myList.Add(new Int_String { _int = 1, _string = "Second Item" });
myList.Add(new Int_String { _int = 2, _string = "Third Item" });
}
}
After that you need to assign this list to your checkedListBox which you will do like this:
public YourForm()
{
PopulateMyList();
checkedListBox1.DataSource = myList;
checkedListBox1.DisplayMember = "_string";
checkedListBox1.ValueMember = "_int";
}
And now when you can manipulate with checked items like this:
for(int i = 0; i < checkedListBox1.Items.Count; i++)
{
if(checkedListBox1.Items[i].CheckedState == CheckState.Checked)
{
int itemValueMember = (checkedListBox1.Items[i] as Int_String)._int;
int itemDisplayMember = (checkedListBox1.Items[i] as Int_String)._string;
//Use these two vars for whatever you need
}
}
TWO IMPORTANT TIPS:
I am not sure for this one since i am writing all this from head but i think that visual studio will not show you that there is DisplayMember or ValueMember for checkedBox component BUT also it will not show error. Reason is that they have hidden in intentionally for idk what reason but it will work.
You are able to assign Display and Value member to a lot of components in winforms BUT for some reason checkedListBox is specific. It is specific because you MUST first assign DataSource to it and then tell it checkedListBox.DisplayMember = "_string" ...... For new guy you will ask why it is important. Simple answer is create custom list for test and add 10k items inside it and then first declare datasource and after it Display and Value member. Test how long form will need to load (get out of freeze state). After that do everything same but first declare Display and Value member and then assign datasource and test again. I am telling this from head without testing but before when i needed about 5k rows with 1st solution it took me about 30 sec and second < 1 sec. If you want to know more about it google it but for now this is pretty much info for you.
A brief intro
The program runs a test on the machines. Then a dialogBox appears asking the user if all the machines worked correctly. If they say no another window appears with the dataGridView asking which machines failed through the checkBox method. This then sets the status to the ERROR status so the program can continue running while ignoring the machines with errors.
I have this class with the two properties
public class ASM
{
public byte DeviceID
public ASMStatus Status
}
I put this in a list
list<ASM001.ASM> ASMs = new list();
Now I want to add this list to a bindingSource in my dataGridView but only those whose Status equals ASMStatus.IDLE
I thought about just creating those that have idle into another list and attaching that to the binding list, however, the dataGridView also has a checkBox column that determines if the status needs to be changed to ASMStatus.ERROR
public partial class FailedMessageBox : Form
{
public FailedMessageBox()
{
InitializeComponent();
DataGridViewCheckBoxColumn col1 = new DataGridViewCheckBoxColumn();
col1.HeaderText = "Device Failed";
dataGridView1.Columns.Add(col1);
}
private void FailedMessageBox_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = Global.ASMs;
}
}
I want to make sure that when the user clicks OK the current ASMs in the list get set to ERROR which is why I thought a bindinglist would work the best
I am wondering if there was a quick way to do this or if I just have to do a bunch of loops.
What about something similar in your Page_load:
using(var context = new DbContext())
{
// You could put a Where Clause here to limit the returns
// i.e. context.ASMs.Where(s => s.Status == ASMStatus.IDLE).Load()
context.ASMs.Load();
var data = context.ASMs.Local.ToBindingList();
var bs = new BindingSource();
bs.DataSource = data;
dataGridView1.DataSource = bs;
}
You should add a BindingSource directly to the page but I am just showing adding it in code. Then you can access it like this:
foreach(DataRow row in dataGridView1.Rows)
{
if ((bool) row.Cells["Device Failed"].Value == true)
{
var line = row.DataBoundItem();
line.Status = ASMStatus.ERROR;
}
}
Make sure you save the changes.
I was trying to output a single List variable that retrieves data from database via a CodeBehind code to a text field in ASPX:
<asp:TextBox ID="TBCluster" runat="server" CssClass="textbox"></asp:TextBox>
C# is used and the code goes something like this:
public List<shuffleDataList> pullShuffledData(SqlDataReader rdr)
{
List<shuffleDataList> callList = new List<shuffleDataList>();
if (rdr != null)
{
if (rdr.HasRows)
{
while (rdr.Read())
{
callList.Add(new shuffleDataList()
{
cluster = rdr.IsDBNull(5) ? null : rdr.GetString(5),
});
}
}
else
{
Response.Write("<script>alert('the data is null')</script>");
return null;
}
}
return callList;
}
The retrieval of cluster field will occur after a user clicks on a particular button and so my passing the variable goes into like the following:
protected void shuffle_Click(object sender, EventArgs e)
{
getdata();
TBCluster.Text = new shuffleDataList().cluster;
}
However nothing is displayed on the textfield. On the same query, I can display the data on a datagrid view but not on a text field? Any ideas why is this occuring?
Thank you
You don't actually appear to be calling your function. Also, since a Text property is generally a string.. you won't be able to assign a list to it (with any meaningful result). Therefore, I will make a heap of assumptions about your code.. and give you this:
var list = pullShuffledData(someReaderHere);
if (list != null)
TBCluster.Text = string.Join(", ", list.Select(x => x.cluster));
I have finally solved my issue:
string cluster = string.Empty;
DataSet ds = new DataSet();
List<shuffleDataList> list = pullShuffledData(rdr);
foreach(shuffleDataList item in list)
{
cluster = item.cluster;
}
TBCluster.Text = cluster;
It was supposed to be displayed early on but this gridview seems to be clearing the value of pullShuffledData once assigned
//gridviewShuffle.DataSource = pullShuffledData(rdr);
//gridviewShuffle.DataBind();
after commenting out, the cluster value finally appeared on text box. thanks
I have a BindingList< KeyValuePair < string, string > > that is bound to a ComboBox control. Based on some conditions, the BindingList will be added a new KeyValuePair. Now, the Newly added item shows up at index 0 of the Combobox, instead of at the end.
While debugging, I found that the BindingList has got the right order. (i.e, the new KeyValuePair is appended)
Also, I check the SelectedValue of the ComboBox in it's SelectedIndexChanged handler and it seems to be not of the ListItem that got selected. Instead, it is that of the supposed ListItem, if the ComboBox had got the right order as in its DataSource, - the BindingList..
The code is a small part of a large project.. Plz let me know if the question is not clear. I can put the relevant parts of the code as per our context.
How could something like this happen? What can I do differently?
I have this class something like this.
public class DropdownEntity
{
//removed all except one members and properties
private string frontEndName
public string FrontEndName
{
get {return this.frontEndName; }
set {this.frontEndName= value; }
}
//One Constructor
public DropdownEntity(string _frontEndName)
{
this.FrontEndName = _frontEndName;
//Removed code which initializes several members...
}
//All methods removed..
public override string ToString()
{
return frontEndName;
}
}
In my windows form, I have a tab control with several tabs. In one of the tabs pages, I have a DataGridView. The user is supposed to edit the cells and click on a Next - button. Then, some processing will be done, and the TabControl will be navigated to the next tab page.
The next tab page has the combobox that has the problem I mentioned. This page also has a back button, which will take back.. the user can modify the gridview cells again.. and click on the next button. This is when the order gets messed up.
I am posting here the Click event handler of the Next Button.. Along with the class, with the rest of the code removed.
public partial class AddUpdateWizard : Form
{
//Removed all members..
BindingList<KeyValuePair<string, string>> DropdownsCollection;
Dictionary<string, DropdownEntity> DropdownsDict;
//Defined in a partial definition of the class..
DataGridView SPInsertGridView = new DataGridView();
ComboBox DropdownsCmbBox = new ComboBox();
Button NextBtn2 = new Button();
Button BackBtn3 = new Button();
//Of course these controls are added to one of the panels
public AddUpdateWizard(MainForm mainForm)
{
InitializeComponent();
DropdownsDict = new Dictionary<string, DropdownEntity>();
}
private void NextBtn2_Click(object sender, EventArgs e)
{
string sqlArgName;
string frontEndName;
string fieldType;
for (int i = 0; i < SPInsertGridView.Rows.Count; i++)
{
sqlArgName = "";
frontEndName = "";
fieldType = "";
sqlArgName = SPInsertGridView.Rows[i].Cells["InsertArgName"].Value.ToString().Trim();
if (SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value != null)
{
frontEndName = SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value.ToString().Trim();
}
if (SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value != null)
{
fieldType = SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value.ToString().Trim();
}
//I could have used an enum here, but this is better.. for many reasons.
if (fieldType == "DROPDOWN")
{
if (!DropdownsDict.ContainsKey(sqlArgName))
DropdownsDict.Add(sqlArgName, new DropdownEntity(frontEndName));
else
DropdownsDict[sqlArgName].FrontEndName = frontEndName;
}
else
{
if (fieldType == "NONE")
nonFieldCount++;
if (DropdownsDict.ContainsKey(sqlArgName))
{
DropdownsDict.Remove(sqlArgName);
}
}
}
//DropdownsCollection is a BindingList<KeyValuePair<string, string>>.
//key in the BindingList KeyValuePair will be that of the dictionary.
//The value will be from the ToString() function of the object in the Dictionary.
DropdownsCollection = new BindingList<KeyValuePair<string,string>>(DropdownsDict.Select(kvp => new KeyValuePair<string, string>(kvp.Key, kvp.Value.ToString())).ToList());
DropdownsCmbBox.DataSource = DropdownsCollection;
DropdownsCmbBox.DisplayMember = "Value";
DropdownsCmbBox.ValueMember = "Key";
//Go to the next tab
hiddenVirtualTabs1.SelectedIndex++;
}
private void BackBtn3_Click(object sender, EventArgs e)
{
hiddenVirtualTabs1.SelectedIndex--;
}
//On Selected Index Changed of the mentioned Combobox..
private void DropdownsCmbBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (DropdownsCmbBox.SelectedValue != null)
{
if (DropdownsDict.ContainsKey((DropdownsCmbBox.SelectedValue.ToString())))
{
var dropdownEntity = DropdownsDict[DropdownsCmbBox.SelectedValue.ToString()];
DropdownEntityGB.Text = "Populate Dropdowns - " + dropdownEntity.ToString();
//Rest of the code here..
//I see that the Datasource of this ComboBox has got the items in the right order.
// The Combobox's SelectedValue is not that of the selected item. Very Strange behavior!!
}
}
}
}
The very first time the user clicks the Next Button, it's fine. But if he clicks the Back Button again and changes the Data Grid View cells.. The order will be gone.
I know, it can be frustrating to look at. It's a huge thing to ask for help. Any help would be greatly appreciated!
Please let me know if you need elaboration at any part.
Thanks a lot :)
I think you have two problems here.
First, if you want to retain the order of the items you should use an OrderedDictionary instead of a regular one. A normal collection will not retain the order of the items when you use Remove method. You can see more info about this related to List here.
You could use such dictionary like this:
DropDownDict = new OrderedDictionary();
// Add method will work as expected (as you have it now)
// Below you have to cast it before using Select
DropDownCollection = new BindingList<KeyValuePair<string, string>>(DropDownDict.Cast<DictionaryEntry>().Select(kvp => new KeyValuePair<string, string>(kvp.Key.ToString(), kvp.Value.ToString())).ToList());
The second problem could be that you change the display name (FrontEndName) of already existing items, but the key is preserved. When you add a new item, try to remove the old one that you're not using anymore and add a new item.
The Sorted Property of the Combobox is set to True! I didn't check that until now. I messed up. Terribly sorry for wasting your time Adrian. Thanks a lot for putting up with my mess here.. :)
I have a method that adds items to my listbox called refreshInterface which is called as soon as the programe starts, adding names of homeforms in the listbox using the FormItems class, here is the rereshInterface method below
public void refreshInterface()
{
//int number = 0;
foreach (DataSet1.xspGetAnalysisUsageTypesRow homeForms in myDataSet.xspGetAnalysisUsageTypes)
{
var forms = new FormItems(homeForms);
listBox1.Items.Add(forms);
}
}
The FormItems class is this below
public class FormItems
{
public DataSet1.xspGetAnalysisUsageTypesRow types { get; set; }
public FormItems(DataSet1.xspGetAnalysisUsageTypesRow usageTypes)
{
types = usageTypes;
}
public override string ToString()
{
// returns the rows that are relating to types.xlib_ID
var libtyps = types.GetxAnalysisUsageRows();
var cnt = 0;
foreach (DataSet1.xAnalysisUsageRow ty in libtyps)
{
//returns true if ty is null
bool typeNull = ty.Isxanu_DefaultNull();
// if its false, if xanu_Default is set
if (!typeNull)
{
cnt += 1;
}
}
var ret = String.Format("set {0} [Set: {1}]", types.xlib_Desc, cnt);
//return this.types.xlib_Desc;
return ret;
}
}
Each listbox (the listbox is on the left of the homeform) item has a number of reports that can be added to it, so for instance, i select an homeform from my listbox, there are 12 textboxes on the right hand side and each textbox has a pair of buttons which are Browse and Clear. If I click on the browse button a new form appears, and i select a report from that form and add it to a particular textbox, the count for that homeform should update, and i clear a textbox for a particular homeform, the count should also update.
At the moment when i debug the application, it shows me the count of each Homeform depending on the amount of reports added to the homeform, but while the programe is running, if i add a new report to a homeform, the count does not update until i restart the debug session. I was told about using a Databinding method but not sure of how i could use it here
How do i ge my listbox item to update ?
You should probably look into binding. Here is a good place to start:
http://www.codeproject.com/Articles/140621/WPF-Tutorial-Concept-Binding
If you want a GUI to respond to data changes then binding is your best friend.
You should bind List Box component source to Observable Collection, every update you do to Observable Collection will update List Box data.
Might not be exact but should give you an idea.
public void refreshInterface()
{
Dictionary<int,string> items = new Dictionary<int,string>();
//int number = 0;
foreach (DataSet1.xspGetAnalysisUsageTypesRow homeForms in myDataSet.xspGetAnalysisUsageTypes)
{
var formitem = new FormItems(homeForms);
items.Add(formitem.someprop, formitem.toString());
}
listbox.DataSource = items;
listbox.DisplayMember = "Value";
listbox.ValueMember = "Key";
}