List to Datatable. Datatable doesn't show any values - c#

I'm trying to make a "history page". Reading the urls a user have been as a string and adding those to List and transform it to DataTable but when I click on the show History menu option all I get is column "urls" and an empty cell underneath it. I assume I'm probably also using the Add method inappropriately.
Main form class:
private void showHistoryToolStripMenuItem_Click(object sender, EventArgs e)
{
using (History history = new History())
{
history.ShowDialog();
nonHomepage = URLInput.Text;
if (String.IsNullOrEmpty(nonHomepage))
{
return;
}
else
{
addToList(nonHomepage);
}
}
}
public void addToList(string URLvalue)
{
listH.Add(URLvalue);
}
public List<string> getList()
{
return listH;
}
History form class:
private void History_Load(object sender, EventArgs e)
{
Form1 br = new Form1();
list = br.listH;
DataTable table = ConvertListToDataTable(list);
dataGridView1.DataSource = table;
}
static DataTable ConvertListToDataTable(List<string> l)
{
DataTable table = new DataTable();
//int columns = 0;
table.Columns.Add("urls");
foreach(string s in l)
{
table.Rows.Add(s);
}
return table;
}
Any suggestions? What if I put all those urls in the file and then read from a file and write to a textbox/table? Or maybe I should change the data structure? Go for dictionaries, for example? Thanks in advance.

When you add a table row, you actually have to add a row, not just a string.
foreach(string s in l)
{
var row = table.NewRow();
row[0] = s;
table.Rows.Add(row);
}
return table;
Also, add a breakpoint and make sure your list isn't empty before converting it, and make sure your table is being populated correctly afterwards.
Additionally, from an architectural standpoint, if you only have one column of information, you shouldn't really be using a DataTable, a List<T> will suffice. Is there some reason that you are using a DataTable here?

Your problem is you create an empty Form1 in the private void History_Load(object sender, EventArgs e) and pass in the listH (which is empty) into the method ConvertListToDataTable(list), hence you have empty grid. The solution is you have to change your History initialization or explicitly call some method LoadData to load the actual list, something like this:
Solution 1
public partial class History : Form {
public History(){
InitializeComponent();
}
public Form1 MainForm {get;set;}
private void History_Load(object sender, EventArgs e) {
var list = MainForm == null ? new List<string>() : MainForm.listH;
DataTable table = ConvertListToDataTable(list);
dataGridView1.DataSource = table;
}
//other code ....
}
//Form1 class
private void showHistoryToolStripMenuItem_Click(object sender, EventArgs e) {
//note the MainForm initialization using Property initializer
using (History history = new History {MainForm = this}) {
history.ShowDialog();
nonHomepage = URLInput.Text;
if (String.IsNullOrEmpty(nonHomepage)) {
return;
} else {
addToList(nonHomepage);
}
}
}
Solution 2
//History class
public partial class History : Form {
//define this method to call explicitly before showing your History dialog
public void LoadData(List<string> list){
DataTable table = ConvertListToDataTable(list);
dataGridView1.DataSource = table;
}
//other code ...
}
//Form1 (or Main Form) class
private void showHistoryToolStripMenuItem_Click(object sender, EventArgs e) {
using (History history = new History()) {
history.LoadData(listH);// <---- call this first to load data
history.ShowDialog();
nonHomepage = URLInput.Text;
if (String.IsNullOrEmpty(nonHomepage)) {
return;
} else {
addToList(nonHomepage);
}
}
}

Alternative syntax to SpikeX's answer:
int i = 0;
foreach (string s in l)
{
table.Rows.Add()
tables.Rows[i].SetField("COLUMN NAME", s);
i++
}
I suppose you only have 1 column in your table, so using SetField might be a bit excessive. But when you have multiple columns it's a bit easier to read, rather than having to go back and check which column has which index.

Related

Adding label with image in datagridview

I am trying to make event viewer using datagridview in c#
This is my target
I am already read many source, and still confused to implement it.
Source
add custom DataGridViewColumn with label and button per cell
How to add a Label to a DataGridView cell
Big thanks for the helps
The following shows how to read images from files, place them into a Dictionary then load them into rows in a DataTable, of course for a real app there are more images and logic to assign the images dependent on your logic.
Note that the image cells can not be selected.
The alternative is to create a custom DataGridViewColumn or the following solution.
Backend mockup
using System.Data;
namespace DataGridViewImages.Classes
{
internal class Operations
{
public static Dictionary<int, byte[]> SmallImages()
{
Dictionary<int, byte[]> dictionary = new Dictionary<int, byte[]>
{
{ 1, File.ReadAllBytes("blueInformation_16.png") },
{ 2, File.ReadAllBytes("radiobutton16.png") }
};
return dictionary;
}
public static DataTable Table()
{
DataTable dt = new DataTable();
dt.Columns.Add("image", typeof(byte[]));
dt.Columns.Add("text", typeof(string));
var images = SmallImages();
dt.Rows.Add(images[1], "Some text");
dt.Rows.Add(images[2], "More text");
return dt;
}
}
}
Form code
using DataGridViewImages.Classes;
namespace DataGridViewImages
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
Shown += OnShown;
dataGridView1.SelectionChanged += DataGridView1OnSelectionChanged;
dataGridView1.RowHeadersVisible = false;
}
private void DataGridView1OnSelectionChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentCell.ColumnIndex == 0)
{
dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex]
.Cells[0].Selected = false;
}
}
private void OnShown(object sender, EventArgs e)
{
dataGridView1.DataSource = Operations.Table();
dataGridView1.Columns[0].HeaderText = "";
dataGridView1.Columns[0].Width = 25;
}
}
}

Register showItems in Database from Main form

This post is related to Populating listview control passing parameters to constructor from another form
Now I need to save items in database. I'm using SQL server as engine database and c# as Language's programming.
Based in answers about the related post I've mentioned at the top from this post, I was doing the functions to get all items of showlistitems from TakenShows.cs but something is wrong with the code.
First able, this is the Main.cs form
public partial class Main : Form
{
private readonly List<ShowItem> showItems;
private List<ShowItem> getItems;
public Main()
{
InitializeComponent();
showItems = new List<ShowItem>();
getItems = new List<ShowItem>();
}
// Button save items
private void button1_Click(object sender, EventArgs e){
var shows = new Takenshows(showItems);
getItems = shows.receiveItems();
foreach(var x in getItems)
{
// Query saving items in database.
SaveItemsLN.getInstance().SaveItems(x.OrderNumber, x.MedDate, x.Values, x.Number);
}
FinishPracticeLN.getInstance().PracticeToFinish();
//TakenShows form should be closed when I click on save items button after getting all items from listview control and it doesn't happen
shows.Close();
Close();
}
//button add items
private void button2_Click(object sender, EventArgs e){
int OrdNum = GetOrdNumberLN.getInstance().GettingOrdNumber();
var show = new ShowItem
//I fix the value assigned to OrderNumber because I have to avoid duplicates keys on Item table.
{
OrderNumber = OrdNum + showItems.Count + 1,
MedDate = DateTime.Now,
F = textBox_F.Text,
PT = textBox_PT.Text,
QT = textBox_QT.Text,
Number = GetNumberLN.getInstance().GettingNumber(),
};
showItems.Add(show);
var frm = Application.OpenForms.OfType<Takenshows>().FirstOrDefault();
if (frm == null)
{
frm = new Takenshows(showItems);
frm.Show();
}
else
{
frm.AddItem(show);
frm.Activate();
}
}
}
When I save items in database, Takenshows form should close and not be opened yet after I click on 'save items' button.
Now this is Takenshows.cs Form when I use the functions to show and save items.
public partial class Takenshows : Form
{
public Takenshows()
{
InitializeComponent();
receiveItems();
}
public Takenshows(IEnumerable<ShowItem> items) : this()
{
AddItems(items);
}
//This method should return a List of type ShowItem that will allow me save the items in database since Main.cs form
public List<ShowItem> receiveItems(){
List<ShowItem> items;
try
{
//Here's the issue (error). On this line code. Cannot cast. Why?
//How can fix this issue?
items = listView1.Items.Cast<ShowItem>().ToList();
return items;
}
catch(Exception ex)
{
throw ex;
}
}
internal void AddItem(ShowItem item) => AddItems(new[] { item });
internal void AddItems(IEnumerable<ShowItem> items)
{
var lvis = items.Select(x => new ListViewItem(new[]
{
x.OrderNumber.ToString(),
x.MedDate.ToString(),
x.Values,
x.Number.ToString()
}));
listView1.Items.AddRange(lvis.ToArray());
}
private void Takenshows_Load(object sender, EventArgs e)
{
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
When I click on save items button, application throws me an exception says "Cannot cast a List of datatype to ". that is the code not works.
How can I do fix these issues? Has anyone the answer to fix the issues?
It's done. All I had to do was to modificate the structure of the stored procedure and column of the Items table on database, replacing varchar by varchar(max).
Then in Takenshows.cs defined the next one method:
public List<ShowList> returnItems(List<ShowList> items){
return items;
}
In Main.cs on save items button (button1)
receiveItems = new Takenshows().returnItems(showItems);
foreach (var x in receiveItems)
{
SaveItemsLN.getInstance().SaveItems(x.OrderNumber, x.MedDate, x.Values, x.Number);
}
I hope my own answer will serve to someone who needs solve difficult issues like is from this post.

ComboBox2 get fields in function of ComboBox1

I have to select one brand of moto. If i select "KTM", i want to get Ktm's motos. If i select "HVA", i want HVA's motos. Etc ..
I have a List of models with all models, and in function what i select, i want to add models by this brand and return this in my ComboBox2.
Modele.cs :
class Modele
{
public string NomModele;
public static List<Modele> lesModeles = new List<Modele>() {
// Husqvarna
new Modele() { NomModele = "TE"},
new Modele() { NomModele = "FE"},
// KTM
new Modele() { NomModele = "EXC"},
new Modele() { NomModele = "EXC-F"}
};
public Modele() { }
public Modele(string NomModele)
{
this.NomModele = NomModele;
}
}
Main.cs :
namespace SuiviEntretien
{
public partial class SuiviEntretien : Form
{
public SuiviEntretien()
{
InitializeComponent();
this.lesMarques.Items.AddRange(Marque.lesMarques.Select(x => x.NomMarque).ToArray());
this.lesModeles.Items.AddRange(Modele.lesModeles.Select(x => x.NomModele).ToArray());
}
private void SuiviEntretien_Load(object sender, EventArgs e)
{
}
private void SauvegarderMoto_Click(object sender, EventArgs e)
{
try
{
Moto maMoto = new Moto(
maMarque.Text = lesMarques.SelectedItem.ToString(),
monModele.Text = lesModeles.SelectedItem.ToString()
);
MessageBox.Show("Moto enregistrée avec succès !", "Information");
tabControl1.SelectTab(MaMoto);
}
catch(Exception)
{
MessageBox.Show("Il manque des informations !", "Information");
}
}
}
}
Thanks for further help.
The following answer has been made with some assumptions, those being:
-You have a ComboBox that contains values, when a value is selected another ComboBox needs to re-populate itself with a new list of data.
Depending on the scale of this problem I would recommend two solutions. Move your data into a relational database and access it accordingly, then populate your first ComboBox as a list of all main keys. (One to many methodology) then populate your second ComboBox according to the first ComboBox value.
Assuming you want to build your list dynamically and want to avoid a database then simply use functionality based on if the ComboBox changes.
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e) {
if (ComboBox1.Text == "KTM")
{
// Populate ComboBox2 with KTM data.
}
else
{
// Populate ComboBox2 with some other data.
}
}
This should help you out.

How can I pass multiple records from one form to another form in C#?

I have 2 forms, form1 and form2. Whenever I double click on a cell of datagrid in form1, it will go form 2 and there I am displaying some items and price of them in a datagrid. I am selecting one row there and that value is passing form 1 datagridview. but I want to pass second valu that also over writing first passed value of form 1. I want to add that in next row. What do I have to do?
Here is my code of form 2
private void Form2_Load(object sender, EventArgs e)// loading data to datagrid from database file
{
SqlDataAdapter sda = new SqlDataAdapter(#"select brnDb.compname as [company name], brnDb.catname as [category Name], itemDB.fullname as [Item Name], itemDb.itmbyp as [Buying Price], itemDB.itmdlrp [Dealer Price],itemDB.itmmrp as [MRP],itemDb.itmunit as [Unit Of Measure], itemDB.itmml [Liters], itemDB.itmgr[KGs], itemDb.itmpc[Units] from brnDB inner join itemDb on brnDb.brname=itemDB.brname order by itemDB.fullname asc", con);
DataTable dt = new DataTable();
DataSet ds = new DataSet();
sda.Fill(dt);
dataGridView1.DataSource = dt;
}
passing selected row with a button click to form 1
private void button1_Click(object sender, EventArgs e)
{
Form1 b = new Form1(dataGridView1.SelectedRows[0].Cells[2].Value.ToString(),
dataGridView1.SelectedRows[0].Cells[3].Value.ToString(),
dataGridView1.SelectedRows[0].Cells[4].Value.ToString(),
dataGridView1.SelectedRows[0].Cells[5].Value.ToString());
b.ShowDialog();
}
Code of form 1
public Form1(string Item_Name, string Buying_Price, string Dealrer_Price, string MRP )
{
InitializeComponent();
int n;
n = dataGridView1.Rows.Add();
dataGridView1.Rows[n].Cells[1].Value = Item_Name;
dataGridView1.Rows[n].Cells[3].Value = Buying_Price;
dataGridView1.Rows[n].Cells[4].Value = Dealrer_Price;
dataGridView1.Rows[n].Cells[5].Value = MRP;
}
So value is being passed from form 2 but overwriting in first row each time. But I want to add new row in form1 before passing.Maybe I want to use some loops here but I don't know how. for looping purpose I took declared a integer also. I googled for that but end up with no good result.
You have to add a List in form1 which can be accessed in form2.
Define Form1 b = null; as global variable
Add b = new Form1(); Form2_Load function
Add b.list.Add(dataGridView1.SelectedRows[0]); to button1_click function before ShowDialog();
Keep only b.ShowDialog(); line in button1_click function
Add public List<DataGridViewRow> list = new List<DataGridViewRow>(); to form1
We can also have another option is to create static class that have generic list . We can use that list as temporary storage.
static class Global
{
private static List<GridRows> _globalVar = new List<GridRows>();
public static void ResetGridData()
{
_globalVar = new List<GridRows>();
}
public static GridRows SetRow
{
set { _globalVar.Add(value); }
}
public static List<GridRows> GetSetting { get { return _globalVar; } }
public class GridRows
{
public string Cell_1 { get; set; }
public string Cell_2 { get; set; }
public string Cell_3 { get; set; }
public string Cell_4 { get; set; }
}
}
This class have public static SetRow setter. Use this setter to save data in global list which is "_globalVar ".
This class also have method to reset that list in any point. Just call that static method to reset that grid.
How to use
This is form2 code that get data and pass to form1.
public partial class Form2 : Form
{
public Form2()
{
//To reset our temporary store on load
Global.ResetGridData();
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Send data from form 2 to form 1
Form1 b = new Form1(dataGridView1.SelectedRows[0].Cells[2].Value.ToString(),
dataGridView1.SelectedRows[0].Cells[3].Value.ToString(),
dataGridView1.SelectedRows[0].Cells[4].Value.ToString(),
dataGridView1.SelectedRows[0].Cells[5].Value.ToString());
b.ShowDialog();
}
}
Receive and save data to our global list in form 1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Form1(string cell1, string cell2, string cell3, string cell4)
{
InitializeComponent();
//Save data to our list using global class that
Global.SetRow = new Global.GridRows()
{
Cell_1 = cell1,
Cell_2 = cell2,
Cell_3 = cell3,
Cell_4 = cell4
};
}
}

How can I take items from a listbox and display them in a listview in another form?

I have a listbox full of items for my order.
I want to take all of the items inside my listbox and transfer them into my listview.
Then I want to take my listview and display it in another form (my messagebox).
My new listview:
private void CustomerInfo_Click(object sender, EventArgs e)
{
ListViewItem customers = new ListViewItem(fullName.Text);
customers.SubItems.Add(totalcount.ToString());
customers.SubItems.Add(total.ToString());
customers.SubItems.Add(Address.Text);
customers.SubItems.Add(telephone.Text);
for (int i = 0; i < OrderlistBox.Items.Count; i++)
{
customers.SubItems.Add(OrderlistBox.Items[i].ToString());
}
Customers.Items.Add(customers);
//CLEAR ALL FIELDS
OrderlistBox.Items.Clear();
fullName.Text = "";
Address.Text = "";
telephone.Text = "";
totalDue.Text = "";
totalItems.Text = "";
}
My contextMenuStrip, so when I click on the customer I can get its info (name, address, order, etc.):
private void customerInformationToolStripMenuItem_Click(object sender, EventArgs e)
{
if (Customers.SelectedItems.Count != 0)
{
var myformmessagedialog = new MessageBoxForm
{
name = Customers.SelectedItems[0].SubItems[0].Text,
address = Customers.SelectedItems[0].SubItems[3].Text,
telephone = Customers.SelectedItems[0].SubItems[4].Text,
};
myformmessagedialog.ShowDialog();
}
}
My new form, the messagebox where I will display all the info for the client:
public partial class MessageBoxForm : Form
{
public MessageBoxForm()
{
InitializeComponent();
}
public string name;
public string address;
public string telephone;
public ListViewItem order = new ListViewItem();
private void MessageBoxForm_Load(object sender, EventArgs e)
{
lblName.Text = name;
lbladdress.Text = address;
lbltelephone.Text = telephone;
orderListView.Items.Add(order);
}
}
I'm sorry if this seems confusing but I'm just looking for help to go in the right direction. Any help is appreciated.
One way to do this is to put the data that you want to display in some sort of ViewModel, basically a class or set of classes that has the data that you want to display. Then the main form can display it, and you can pass a reference to that ViewModel to the message box and it can display it as well.
In general you want to avoid any kind of code that directly ties controls from different forms together.
The easiest way based on your current setup is to simply pass your list view data across to your MessageBoxForm e.g.
public partial class MessageBoxForm : Form
{
...
public void LoadListView(ListViewItemCollection items)
{
orderListView.Clear();
orderListView.AddRange(items);
}
}
....
private void customerInformationToolStripMenuItem_Click(object sender, EventArgs e)
{
if (Customers.SelectedItems.Count != 0)
{
var myformmessagedialog = new MessageBoxForm
{
name = Customers.SelectedItems[0].SubItems[0].Text,
address = Customers.SelectedItems[0].SubItems[3].Text,
telephone = Customers.SelectedItems[0].SubItems[4].Text,
};
myformmessagedialog.LoadListView(Customers.Items);
myformmessagedialog.ShowDialog();
}
}
Basic answer is you don't.
You maintain a collection of items (whatever they are).
You display them in a list box.
You display them in a list view.
If you want say select some from the list box and only move them to the list view.
Then you use the listbox selection to find them in your collections of items, create a list of selected ones then passs that to the form with the listview to display.
Don't use UI controls to store your data and try really hard to never make one form's UI directly dependant on another.
I'm guessing what you'd need (and I could have misunderstood what you are looking for) is a new method in you MessageBoxForm to pass in your Customers object:
private void customerInformationToolStripMenuItem_Click(object sender, EventArgs e)
{
if (Customers.SelectedItems.Count != 0)
{
var myformmessagedialog = new MessageBoxForm;
myformmessagedialog.Customers = Customers;
if (myformmessagedialog.ShowDialog() == DialogResult.OK)
{
Customers = myformmessagedialog.Customers;
}
}
}
If so, simply modify your class to be something like this:
public partial class MessageBoxForm : Form
{
public MessageBoxForm()
{
InitializeComponent();
}
private void MessageBoxForm_Load(object sender, EventArgs e)
{
if (Customers != null)
{
// add your code here to add your Customers as needed
}
}
public Customers Customers { get; set; }
}
To access anything from the parent form you need to pass it to the child form so
myformmessagedialog.ShowDialog();
becomes
myformmessagedialog dialog = new myformmessagedialg(this);
dialog.ShowDialog();
and your class constructor becomes this:
public MessageBoxForm(myformmessagedialog parent){
name=parent.fullName.Text;
address=parent.address.Text;
...etc...
InitializeComponent();
}
Though it might be better to just pass in the name, address, etc rather than the whole form, this way is nice for while you are changing things because you have one less place to change to add another variable to pass.

Categories