WPF: How to access specific DataTable from a different window - c#

I am creating a WPF Application that has 2 windows.
In Window_1 i have a button that imports an excel document and stores corresponding fields in a DataTable. After this excel document has been successfully imported i want to prompt user to view the document. If the user says 'Yes' then Window_2 is loaded.
In Window_2 there is a DataGrid and i want it to be populated using the DataTable in Window_1?
How do i populate the DataGrid in Window_2 using data stored in the DataTable in Window_1

i think i have found a solution to my problem. (I have derived this solution from ASh's response.)
In Window_1
DataTable maindata = new DataTable(); //datatable with imported excel data
//button click event to prompt user to view Window_2
private void yes_Click(object sender, RoutedEventArgs e){
var w2 = new Window { dt = maindata };
w2.Show();
}
In Window_2
public DataTable dt { get; set; }
private void Window_Loaded(object sender, RoutedEventArgs e)
{
dtGrid.ItemsSource = dt.DefaultView; //dtGrid is the DataGrid
}
So here is what i think.
Upon click 'Yes' (yes_Click) the data in maindata DataTable is equated to the data in dt DataTable (present in Window_2). The latter DataTable gets the data of maindata DataTable and loads it into DataGrid dt.
I thought i should put out my findings in case another person runs into the same problem.
Thank you all.

You could give the data from window 1 to window 2 like this:
var data = //your data;
Window_2 window = new Window_2(data);
window.Show();
//then in window 2
public Window_2(var data){
InitializeComponent();
this._fieldWithData = data;
}
So make a constructor overload where you pass the data. Then you can pass through the data from the different windows. StackOverflow is here to help to figure out on how to actually fill the datagrids, plenty of posts about that! Hope that helps!

This is the version of the code that works for me in a similar scenario.
In the first Window, in .xaml.cs I would place this:
DataTable myDataTable=new DataTable();
//fill in myDataTable with anything you want. Your case is Excel data
private void btnExtractComplementaryBOM_Click(object sender, RoutedEventArgs e)
{
ShowDataGrid window2 = new ShowDataGrid(myTable) ; //open up an instance of an existing Window called ShowDataGrid. Pass to it as an argument the dataTable object which embeds data from your Excel
ShowDataGrid.Show();
}
In the second Window (which can be customized as you wish by its .xaml).
You should have the following lines of code in ShowDataGrid.xaml.cs
public partial class ShowDataGrid : Window //2nd Window is called "ShowDataGrid" here
{
public DataTable dataTable2; //declare a public datatable variable
public ShowDataGrid(DataTable dataTable2)
{
InitializeComponent();
datagridName.ItemsSource = dataTable2.DefaultView;
}
}

From one window you can get the other window by name, then get the datagrid by name (as long as you have named everything).
Window w = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.Name == "windowname");
DataGrid dg = (DataGrid)w.FindName("datagridname");
Then 'dg' is a reference to the datagrid that you want.

Related

How to bind Access database to DataTable?

I'm new to C# and Visual Studio.
I'm working on a project that is searching through a database of information.
I want to bind a database (Microsoft access file) to my datagridview
but I want it to work with my preexisting code which utilizes a datatable converted into a dataview.
My database has a lot of information and I don't want to put it in manually. I've tried binding the information directly to the datagridview (through datasource in the properties) but then searching doesn't work**. I've looked into sql but im trying to avoid learning 2 languages at the same time.
My projects basic functionality contains: 1 combobox (idCbo) containing the search query's 1 datagridview for displaying the information
this setup is for searching one column only, im going to duplicate the code for the oher columns
The name of the column in the datagridview selects the column(id) for filtering then the combo box(idCbo) searches that column for matching characters in the datagridview and comboBox list.
the combo box contains the values 1-100 for searching the column
public partial class Form1 : Form
{
DataTable dt = new DataTable();
DataView dataView;
public Form1()
{
InitializeComponent();
dt.Columns.Add("id", typeof(int));
for (int i = 0; i < 100; i++)
dt.Rows.Add(i);
dataView = new DataView(dt);
this.dataGridView1.DataSource = dataView;
}
private void idCbo_SelectedIndexChanged(object sender, EventArgs e)
{
string query = idCbo.Text;
dataView.RowFilter = $"convert(id,'System.String') LIKE '%{query}%'";
}
}
**
Binding the database to the datagridview while using this code renders column titles but not the information and the code cannot access the database, columns or the rows System.Data.EvaluateException: 'Cannot find column ...
Big thanks to Johng for assisting me with the code :)
CURRENT WORKING CODE
public Form1()
{
InitializeComponent();
}
public static BindingSource gridBindingSource;
private void idCbo_SelectedIndexChanged(object sender, EventArgs e)
{
string query = idCbo.Text;
gridBindingSource = (BindingSource)dataGridView1.DataSource;
if (gridBindingSource != null)
{
if (query == "All")
{
gridBindingSource.Filter = "";
}
else
{
gridBindingSource.Filter = "convert(id,'System.String') LIKE '%" + query + "%'";
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the '_InfoFinalv_2___CopyDataSet.Info' table. You can move, or remove it, as needed.
infoTableAdapter.Fill(this._InfoFinalv_2___CopyDataSet.Info);
idCbo.Items.Add("All");
for (int i = 1; i < 100; i++)
{
idCbo.Items.Add(i);
}
idCbo.SelectedIndex = -1;
}
private void idReset_Click(object sender, EventArgs e)
{
idCbo.SelectedIndex = -1;
}
If you have set up the grids data source in the designer “correctly” then using the DataView as you want can be simplified by using the existing BindingSource that is usually created when you set up the grid’s data source in the designer.
We can use the existing grid’s BindingSource and then use it’s Filter property as opposed to converting the BindingSource to a DataView to filter. This will allow us to set the filter in the grid WITHOUT having to “change” the grids data source.
Remove all the code you have in the form constructor obviously leaving the InitializeComponent(); and add the code below to the forms Load event. In the load event all we do is set up the combo box with the proper values. I added an “All” option to allow the user to “un-filter” the data in the grid.
private void Form1_Load(object sender, EventArgs e) {
// TODO: This line of code loads data into the 'database1DataSet.EmployeeDT' table. You can move, or remove it, as needed.
employeeDTTableAdapter.Fill(this.database1DataSet.EmployeeDT); // <- created by the designer
idCbo.Items.Add("All");
for (int i = 1; i < 100; i++) {
idCbo.Items.Add(i);
}
idCbo.SelectedIndex = 0;
}
Then in the combo boxes SelectedIndexChanged event... change the code as shown below. Cast the grids DataSource to a BindingSource and then use its Filter property.
private void idCbo_SelectedIndexChanged(object sender, EventArgs e) {
string query = idCbo.Text;
BindingSource GridBS = (BindingSource)dataGridView1.DataSource;
if (GridBS != null) {
if (query == "All") {
GridBS.Filter = "";
}
else {
GridBS.Filter = "EmpID LIKE '%" + query + "%'";
}
}
}
Here's the tip:
On the form load, make an ajax call to the database and fetch only the required data columns. Return data will be in JSON that can be used as data for DataTable.
I used it in an MVC project recently and it works fine. If you would like I can share the detailed code and logic.
Not sharing the code since I'm not sure if you are on .Net MVC.

Calling textbox information from one form to another

I have 2 forms: The first form has textboxes that display different task names and times spent on each task. The second form has a datagridView. Using:
public void DataTableTest()
{
//Create DataTable
DataTable dt = new DataTable();
//Add Columns
dt.Columns.Add("Task Name", typeof(string));
dt.Columns.Add("Time Worke (HH:mm:ss)", typeof(string));
//Add Rows
dt.Rows.Add();
dataGridView1.DataSource = dt;
}
I am able to get the data table layout the way I want. My issue is, I want to pull the textbox.text from Form1 to populate the [0][0] cell of the data table. Something like:
//Add Rows
dt.Rows.Add();
dt.Rows[0][0] = Form1.tasktextbox1.text;
dataGridView1.DataSource = dt;
But this is not working. I am getting the following from my error list when I try to start the program:
'TaskTracker.Form1.TaskTextBox1' is inaccessible due to its protection level.
Thank you in advance for the assistance. If you have any questions ask, first time posting and new to programming.
The error describes itself: TaskTextBox1 is a private member of Form1 and you cannot call it on another class. Add a property to Form1:
Public string task1text { get { return this.textbox1.text; }}
and then use it on the other form:
dt.Rows[0][0] = Form1.task1text;
I was able to complete this task with:
public static string task1text;
public void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
task1text = TaskTextBox1.Text;
ReportForm RF = new ReportForm();
RF.Show();
}
on form1 and using Roozbeh's suggestion on the second form:
dt.Rows[0][0] = Form1.task1text;
Thank you all for your assistance. Slowly figuring it out! :)

Getting previous version of row text in bindingsource before AcceptChanges

I have a small Winforms program that I'm testing with. What I'm trying to do is get the row text before changes were made in the datagridview row. Right now, in the actual program (not this test version), when the user presses 'Save' I am updating records in a database. However, the users would like a log of the values before they were changed. That's what I'm trying to figure out... how to get the values before they were changed.
The UI looks like this:
The code looks like this:
using System;
using System.Data;
using System.Windows.Forms;
namespace DataGridViewDemo
{
public partial class Form1 : Form
{
public DataTable DataTable { get; set; }
public Form1()
{
this.InitializeComponent();
// Initialize table and populate with data.
this.DataTable = new DataTable();
this.DataTable.Columns.Add("Name", typeof(string));
this.DataTable.Columns.Add("Age", typeof(int));
this.DataTable.Rows.Add("Tom", 45);
this.DataTable.Rows.Add("Erin", 36);
this.DataTable.Rows.Add("Tom, Jr.", 9);
this.DataTable.AcceptChanges();
// Bind the datasource to the data table.
this.bindingSource1.DataSource = this.DataTable;
this.dgv.DataSource = this.bindingSource1;
}
private void btnSave_Click(object sender, EventArgs e)
{
// Get all changes made to the rows.
var changes = ((DataTable)this.bindingSource1.DataSource).GetChanges(DataRowState.Modified);
if (changes == null)
{
return;
}
// Now I've got every row change to the data table...
var changedRows = changes.Rows;
//.. but how can I get the same rows /before/ they were changed?
}
}
}
I've tried using the CurrentCellDirtyStateChanged event, but it fires on every keystroke in a cell. I'm wondering if the binding source contains a before image of the datatable before I AcceptChanges on it (which I'm not doing yet, in the program above).
When changes are made to data rows, the dataset retains both the original (Original) and new (Current) versions of the row. For example, before calling the AcceptChanges method, your application can access the different versions of a record (as defined in the DataRowVersion enumeration) and process the changes accordingly.
http://msdn.microsoft.com/en-us/library/7kd9zhee.aspx

Enquiry about reportViewer taking parameters from a form

I'm quite new to using ReportViewer. I have a problem that I do not know how to solve.
I have a Date TextBox and a Location TextBox. My problem is that, when the user keys in the date and location, how do I display the same data in the ReportViewer. Below are some screenshots for better understanding. Any help will be appreciated.
Please let me know if more details are required.
I am assuming you'll add a ShowButton button to your Form. However, you can use TextBox event (e.g. Focus Lost, Text Changed etc) instead of button click event.
private void ShowButton_Click(object sender, EventArgs e)
{
DateTime allocationDate = Convert.ToDateTime(allocDateTextBox.Text);
string locationName = locationTextBox.Text;
//You can create as many datasources matching the name of DataSet in your report
ReportDataSource rds = new ReportDataSource("DataSet1");
rds.Value = getData(String.Format("Select * from myTable where theDate={0} AND Location={1}", allocationDate, locationName));
reportViewer1.LocalReport.DataSources.Clear();
//add as many datasources created above
reportViewer1.LocalReport.DataSources.Add(rds);
reportViewer1.RefreshReport();
}
private DataTable getData(string query)
{
//Select new record from database based on the new query with the new criteria
//return the record as DataTable, DataSet or Collection of object
}

Infragistics Ultragrid - Combobox as column

I have a problem with the UltraGrid control from Infragistics. I have created a ultracombobox with a few values in it:
UltraCombo ultraComboPaneel = new UltraCombo();
ultraComboPaneel.DataSource = articleList;
ultraComboPaneel.ValueMember = "ArticleID";
ultraComboPaneel.DisplayMember = "Name";
Now I have an UltraGrid, and I want to put the ultraCombo in a cell so I can choose one of the items of the ultracombo as a cell value. I tried it both in code and in the ultragrid designer but i can't seem to find a way to do it.
Any of you got an idea? More information can be provided if needed
Edit:
I found something like
UltraGridColumn ugc = ultraGridTypePaneel.DisplayLayout.Bands[0].Columns.Add("combo");
ultraGridTypePaneel.DisplayLayout.Bands[0].Columns["combo"].EditorControl = ultraComboPaneel;
I feel I'm on the right way but it is still not showing on the screen...
The UltraCombo provides a great deal of functionality. If all you need is the ability to choose an item from a list, you might find the grid's ValueLists provide a better solution.
Here's some code to get you started:
private void myGrid_InitializeLayout(object sender, Infragistics.Win.UltraWinGrid.InitializeLayoutEventArgs e)
{
const string colorValueList = #"ColorValueList";
if (!e.Layout.ValueLists.Exists(colorValueList))
{
ValueList svl = e.Layout.ValueLists.Add(colorValueList);
svl.ValueListItems.Add(1, "Red");
svl.ValueListItems.Add(2, "Green");
svl.ValueListItems.Add(3, "Blue");
}
e.Layout.Bands[0].Columns["Color"].ValueList = e.Layout.ValueLists[colorValueList];
}
You could find at the link below some approaches that you could use to put a DropDown into a UltraGrid cell:
http://devcenter.infragistics.com/Support/KnowledgeBaseArticle.aspx?ArticleID=7841
Going back to your current code snippet - you are almost there:
First you should set the binding context of your UltraCombo to the BindingContext of the form the your UltraCombo will be used like:
ultraComboPaneel.BindingContext = this.BindingContext;
Please note that setting binging context should happen prior setting your control to be EditorControl. One more thing that I noticed is that the property currently is changed to EditorComponent so I believe that you are using older version of the Infragistics components. However you should still be able to use the very same approach. I have created small code snippet showing the above with code:
public partial class Form1 : Form
{
UltraCombo uc;
public Form1()
{
InitializeComponent();
DataTable dt = new DataTable();
dt.Columns.Add("Int", typeof(int));
dt.Rows.Add(1);
dt.Rows.Add(1);
dt.Rows.Add(1);
DataTable dtt = new DataTable();
dtt.Columns.Add("Int", typeof(int));
dtt.Rows.Add(2);
dtt.Rows.Add(2);
dtt.Rows.Add(2);
uc = new UltraCombo();
uc.BindingContext = this.BindingContext;
uc.DataSource = dtt;
ultraGrid1.DataSource = dt.DefaultView;
}
private void ultraGrid1_InitializeLayout(object sender, Infragistics.Win.UltraWinGrid.InitializeLayoutEventArgs e)
{
e.Layout.Bands[0].Columns[0].EditorComponent = uc;
}
}
Hope this helps.
I use the Ultra Dropdown instead.
dim udd As UltraDropDown
udd = New UltraDropDown
With udd
'add data binding or value list items here
End With
Me.ultragrid.DisplayLayout.Bands(0).Columns("Column Name").ValueList = udd
The key is the last line that assigns the "Value List" of the ultra grid column to the Drop down control.

Categories