I have this code, in which I read the data i deserialized in a gridview, let's name it FormReadDatabases
It gets populated like this:
xmlData = (xml.ServiceConfig)serializer.Deserialize(reader);
dataGridView1.DataSource = xmlData.Databases;
Then in each row of the grid I have a button 'Tables'
After I click it a new form appears FormReadTables
It gets populated like this:
BindingList<xml.Table> table = new BindingList<xml.Table>();
dataGridView4.DataSource = table;
Then I have a button which helps me add a new table, it works fine, the new row appears in the FormReadTables, But when i close the form and I am now at the FormReadDatabases if I click again on the Table button the changes are not saved.
Any idea how to avoid this?
This should be simple, data binding needs to happen using a mechanism that can hold value even when forms are opened or closed:
First way could be use a static type as follows:
static BindingList<xml.Table> table;
public BindingList<xml.Table> FetchTable()
{
if(table == null)
{
table = new BindingList<xml.Table>();
}
return table
}
dataGridView4.DataSource = FetchTable();
There's a catch out here what if the form can have multiple instances than can access the static variable, then while updating the table type it needs to be locked / synchronized
Another option would be table type is part of the main form, which loads the child form and in the constructor of the child form it gets the instance of the parent form, which is used updated and is retained even after closing child form. This will also need synchronization for multiple user / thread access
public class ParentForm
{
public BindingList<xml.Table> table = new BindingList<xml.Table>();
}
public class ChildForm
{
ParentForm localPf;
pulic ChildForm(ParentForm pf)
{
localPf = pf;
}
dataGridView4.DataSource = localPf.table;
}
Noe any change to parent form object's table variable will persist till the point Parent form is in the memory, but please note this implementation is not yet threads safe
Each time the form opens, you are creating a new BindingList.
BindingList<xml.Table> table = new BindingList<xml.Table>();
Instead, have the other page contain a variable for this, and when you 'new' the other form, pass in the variable.
The Actions taken on the opened form are byref, and therefore will update your host forms variable. This means the next time you open the form, the variable you pass to it will already have the previous changes already stored in it.
Example as requested:
I don't have my WinForms environment at hand, but this shows the important concepts.
namespace Bob
{
public class FormLucy
{
private BindingList<xml.Table> table = new BindingList<xml.Table>();
// your form stuff..
protected void ButtonClick(object sender, EventArgs e)
{
var frm = new FormTracy(table);
// init your forms properties, position etc
fmr.ShowDialog();
}
}
}
Related
Say I have a list called listOfFruits in my main form. In a second form I've made I want the user to be able to remove items from that list to a second list called removedFruits. Currently I know I can access these lists in my second form simply passing them as parameters in the form constructor. However c# can't do pointers (correct?) so how can I effect the main form's copy of these lists from my second form? Because currently any changes to those lists in my second form don't effect the main form's original copy of the lists. If I were to remove 5 fruits from the listOfFruits passed to my second form then after finishing my work the main form would still still have a full listOfFruits and an empty removedFruits. Is there a simple fix to this? Maybe a get/set or a way to add/remove items from the original lists from the second form? Maybe the answer is in some sort of accessor stuff?
EDIT: To clarify; I want to add to one list, and remove from another. Not add/remove to the same list. Not sure if this matters entirely but I figured I'd be specific here in case it does.
EDIT2: I think the issue is I'm copying the original list from the first form and not editing it directly. Can someone fix my code so I can access the original list from my second form instead of making a copy of the list?
public partial class ListSelector : Form
{
private string windowName = Form1.typeOfModuleAdded;
public List<IOModule> innerIOList;
IOModule cardAdded = null;
public ListSelector(List<IOModule> cardList)
{
this.Text = windowName;
innerIOList = cardList;
InitializeComponent();
InitializeList();
}
private void InitializeList()
{
if (windowName == "Drive")
{
string[] listDrives = { "ACS880", "test" };
listBox1.Items.AddRange(listDrives);
}
else if (windowName == "IOBlock")
{
if (!innerIOList.Any())
{
MessageBox.Show("No cards loaded! Please import cards from IO List.", "Error Empty Data", MessageBoxButtons.OK, MessageBoxIcon.Error);
this.Close();
}
foreach (IOModule card in innerIOList)
{
cardAdded = card;
listBox1.Items.Add(card.name);
}
}
else if (windowName == "Local Card")
{
string[] listLocals = { "1756-EN2T", "test" };
listBox1.Items.AddRange(listLocals);
}
else if (windowName == "Processor")
{
string[] listProcessors = { "1756-L71S", "test" };
listBox1.Items.AddRange(listProcessors);
}
}
private void addBtn_Click(object sender, EventArgs e)
{
if (listBox1.SelectedItem != null)
{
Form1.SetModule(listBox1.SelectedItem.ToString());
Form1.confirmedAdd = true;
this.Close();
}
else if (cardAdded != null)
{
innerIOList.Remove(cardAdded);
}
else
{
MessageBox.Show("No module selected!");
}
}
and here's how I pass the list to that form from my first form:
ListSelector test = new ListSelector(ioList);
test.ShowDialog();
where ListSelector is the name of my second form, and ioList is the list im passing to it.
EDIT3: added more code
"However c# can't do pointers (correct?) so how can I effect the main form's copy of these lists from my second form?"
No, not correct. Any object reference (for instance, of a List<Fruit>) is still very much a pointer to a place in memory, and if you pass the same List<Fruit> object to both Forms, they share the same List.
I don't know why your changes to your listOfFruits don't chow up in your first Form. I would check the following things:
Are you 100% sure you use the same List<Fruit> object in both Forms. (If you create a new List like this: new List<Fruit>(listOfFruits) it is NOT the same List)
Does the first Form have any way of finding out, that the List has changed? Possible using a Timer with recurring checks, or (my favorite) triggering an event when you change something, and subscribe an EventHandler in the first Form to the event.
I assume that you have created a second list in your second form that is filled with the items of the first form's list. Then changes on the second list aren't reflected in the first list. You have to use the same reference of the list.
public Form2(List<Fruit> listOfFruits)
{
this._listOfFruits = listOfFruits;
}
private List<Fruit> _listOfFruits;
Instead using a public field, try to use property and on creating your new ListSelector pass the list to the property.
public partial class ListSelector : Form
{
private string windowName = Form1.typeOfModuleAdded;
private List<IOModule> innerIOList;
IOModule cardAdded = null;
public List<IOModule> CardList
{
get
{
return innerIOList;
}
set
{
innerIOList = value;
InitializeList();
}
}
public ListSelector()
{
this.Text = windowName;
InitializeComponent();
}
When creating your new ListSelector object
ListSelector ls = new ListSelector();
ls.CardList = your mainform list of IOModule here
ls.ShowDialog();
In my project on the WindowsForms, if I have a static instance inside the form, when I'm opening my form at the first time, it works. But if I'll close it and open again, the form will be empty. Why can it be?
public partial class Computer : Form
{
static Indicators indicators = new Code.Indicators();
}
P.S. I'm making it static, because I want to save it's value after the form will be closed.
Edit 1: Opening the form
private void button3_Click(object sender, EventArgs e)
{
Computer computer = new Computer();
computer.ShowDialog();
}
Edit 2: Computer Form
namespace WF
{
public partial class Computer : Form
{
static Code.Indicators indicators = new Code.Indicators();
public Computer()
{
if (indicators.isComputerAlreadyRunning == false)
{
InitializeComponent();
pictureBox1.Image = Properties.Resources.Computer1;
indicators.isComputerAlreadyRunning = true;
}
}
// My not successful try to save the value of the variable
public Code.Indicators ShowForm()
{
return new Code.Indicators(indicators.isComputerAlreadyRunning);
}
}
}
I don't think that static members work well with the Windows Form lifecycle.
I suggest you make Indicators a normal instance member of your form. To preserve state beyond the life of a form you can copy your state from the form and copy it back to the form when you open it.
// Keep this in the proper place
var indicators = new Code.Indicators();
...
// Copy back and forth for the life time of the form
using (var form = new Computer())
{
form.Indicators.AddRange(indicators);
form.Close += (s, e) =>
{
indicators.Clear();
indicators.AddRange(form.Indicators);
}
}
...
According to the constructor in the Computer class, the indicators.isComputerAlreadyRunning is set to true the first time the form is created.
So when Computer is created the second time, the if condition will fail and the whole if block will be skipped. That means your InitializeComponent(); won't get run and hence nothing in the form will shows up.
Put the InitializeComponent(); outside the if clause to make it work.
I'm developing a WPF C# application and I have a strange behaviour in modification of objects. I try to explain it in general way.
Suppose that you have an object of a class described as follows:
public class A
{
int one;
bool two;
List<B> listofBObjects;
}
where B is:
public class B
{
int three;
int four;
}
I pass an instance of A class and an instance of B class from a window to another, only defining two variables of type A and B in the second window and passing them before the Show() method, with the following code, executed into an instance of window FirstWindow:
SecondWindow newWindow = new SecondWindow();
newWindow.instanceOfA = this.instanceOfA; //instanceOfA is of type A
newWindow.instanceOfB = this.instanceOfA.listOfBObjects[0]; //instanceOfB is of type B
newWindow.Show();
If I have to repeat this code twice(that is, opening twice the window), in the first execution everything works as expected, infact if I modify values in instanceOfB variable, I see the modification also in instanceOfA variable. But, in the second execution, the modification in instanceOfB does not affect instanceOfA...
The modifications are done in newWindow. For example:
this.instanceOfB.three++;
this.instanceOfB.four--;
Imagine that you are in the FirstWindow. Click on a button and SecondWindow opens, passing both variables as described above. In SecondWindow, do some modifications, click on OK and SecondWindow closes, returning control to FirstWindow. If I reclick on the same button, I reopen SecondWindow. If I do modifications now, they do not affect both variables.
I try to have a look (in VS2012) at both variables in the console with control expression and I see that, in the first pass of code, both variables changes when code above is executed but, in the second pass of code, only instanceOfB changes...
EDIT:
Following the code that I use to pass parameters to SecondWindow...types are explaind below
IntermediatePosition obj = ((FrameworkElement)sender).DataContext as IntermediatePosition; //IntermediatePosition is Class B
IntermediatePositionsSettingsWindow ips = new IntermediatePositionsSettingsWindow();
ips.currentIntermediatePosition = obj;//this is the instanceOfB
ips.idxOfIpToModify = obj.index;
ips.currentSingleProperty = this.currentPropertyToShow; //this is the instanceOfA object
ips.sideIndex = this.sideIndex;
ips.ShowDialog();
Consider that obj is given by a button selection into a datagrid, in which each row represents an IntermediatePosition object. In the datagrid, there is a column button and, clicking by buttons, IntermediatePositionsSettingsWindow is opened with the proper data
EDIT:
I've performed the folloqing check:
this.currentPropertyToShow.sides[this.sideIndex].intermediatePositionList[i].GetHashCode() == obj.GetHashCode()
where i is the index of related IntermediatePosition object. At first usage of IntermediatePositionsSettingsWindow the objects result equals, but in second usage they are different
Why this thing happens?
If it is needed any other clarification, I will edit the question
Thanks
It's difficult to give a proper answer to this, as there is insufficient code to correctly work out the issue. However, if you are databinding, then I believe you need to implement this interface. It is possible that you're issue is simply that you're model is not reflecting the changes to the screen.
I can't reproduce your problem. Here's a simplified representation of your class relation (as I understood from your question). Please let us know if this is correct:
public partial class MainWindow : Window
{
internal A instanceOfA;
internal B instanceOfB;
public MainWindow()
{
InitializeComponent();
instanceOfB = new B() { };
instanceOfA = new A() { listOfBObjects = new List<B>() { instanceOfB } };
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SecondWindow newWindow = new SecondWindow();
newWindow.instanceOfA = this.instanceOfA; //instanceOfA is of type A
newWindow.instanceOfB = this.instanceOfA.listOfBObjects[0]; //instanceOfB is of type B
newWindow.Show();
}
}
public partial class SecondWindow : Window
{
internal A instanceOfA;
internal B instanceOfB;
public SecondWindow()
{
InitializeComponent();
Loaded += SecondWindow_Loaded;
}
void SecondWindow_Loaded(object sender, RoutedEventArgs e)
{
MessageBox
.Show(String.Format("{0}",
this.instanceOfB == this.instanceOfA.listOfBObjects[0]));
this.instanceOfB.three++;
this.instanceOfB.four--;
}
}
Note: this is not an answer, just trying to establish some common ground for further discussions, as comments don't leave you enough freedom for code samples.
Thanks to #pm_2 and #BillZhang comments, I found a row in my code in which this.currentPropertyToShowwas edited. After the returning back at first window, infact, I perform the refresh of the window, but it is not needed to edit this.currentPropertyToShow, so I have commented it and everything works!
Thanks everybody for precious comments and suggestions!
I have a dataset that is being created inside of a windows form we'll call form1. I want this dataset to populate a DataGridView that exists in a separate form we'll call form2.
I've tried setting up the datasource like so, but it doesn't work because the context is incorrect.
newShipmentGrid.DataSource = dataToWatch;
Specifically, the error I get is "The name newShipmentGrid does not exist in the current context". This is a Windows page form application.
Here is a very simple implementation from some old code of mine for a Windows Forms Application. The constructor takes a DataSet from the calling procedure (another form) as the sole parameter, sets a DataSet member to the value of the parameter, and fills the data set with the method 'FillDataGrid'. Hope this helps you out.
public partial class HistForm : Form
{
DataSet data;
public HistForm(DataSet ds)
{
data = ds;
InitializeComponent();
FillDataGrid();
}
private void FillDataGrid()
{
dataGridView1.DataSource = data.Tables[0];
}
}
The calling method for this form:
private void btnHist_Click(object sender, EventArgs e)
{
DataSet tempDataSet = new DataSet();
tempDataSet = userData;
tempDataSet.Tables[0].Columns.RemoveAt(1); //remove columns 0 and 1 for display purposes
tempDataSet.Tables[0].Columns.RemoveAt(0);
HistForm hForm = new HistForm(tempDataSet);
hForm.Show();
}
You would have to pass the variables into the second form and then populate the grid in the page load event.
Here is a good link to begin with:
http://msdn.microsoft.com/en-us/library/6c3yckfw(v=vs.100).aspx
There is a MenuItem click event MainMenu_Define_Material which opens a window called Material. I get info from a textbox called txt_density and I save that info in density and return to main window via OK-button having click event Material_btn_OK_Click.
My question is, how I can avoid passing the last session values every time I open the window Material?
I want, once density is set, every time I open Material window I want to see the values of previous session.
private void MainMenu_Define_Material(object sender, RoutedEventArgs e)
{
newWin_material = new Material();
newWin_material.btn_OK.Click += new RoutedEventHandler(Material_btn_OK_Click);
if (density != -1)
{
newWin_material.txt_density.Text = density.ToString();
}
newWin_material.ShowDialog();
}
private void Material_btn_OK_Click(object sender, RoutedEventArgs e)
{
density = System.Convert.ToSingle(newWin_material.txt_density.Text);
newWin_material.Close();
}
Not very clear where that density comes from, but you can insert that field in uour data class what you can hold on data layer or may be like ObjectDataProvider for modelview.
There are a lor of different solutioms our there. The basic idea is:
Define common, shared data storage and keep there alll values you want to share between different windows.
Define a data class. I used here a static class with a static member Desnity.
public static class DataClass
{
public static double Desnsity;
}
After in any window you're able to access that field (read/write), like
DataClass.Density
Hope this is clear.
There is no concept of Session in WPF. You can try creating a static variable to do this or a app config value or pass a parameter via the constructor.
If you are going to new it ( e.g. new Material(); ) then it is going to start with zero information. That is what new does. What is wrong with passing the value in the ctor?
Try
MainWindow
{
private newWin_material = new Material(); // just new it ONCE
// this may need to be in MainWindow ctor.
newWin_material.btn_OK.Click += new RoutedEventHandler(Material_btn_OK_Click);