Using a class initiated in one method in another method - c#

I have a C# WPF app that every time the user opens a new file, the contents are displayed in a datagrid.
public partial class MainWindow : Window
{
public TabControl tc = new TabControl();
public MainWindow()
{
InitializeComponents();
}
private FromFile_click(object sender, RoutedEventArgs e)
{
//gets information from file and then...
if (numberOfFiles == 0)
{
masterGrid.Children.Add(tc);
}
TabItem ti = new TabItem();
tc.Items.Add(ti);
DataGrid dg = new DataGrid();
ti.Content = dg;
dg.Name = "Grid"+ ++numberOfFiles;
dg.ItemSource = data;
}
private otherMethod(object sender, RoutedEventArgs e)
{
}
}
My question is, how do I use the data in dg in the method "otherMethod"? Also, is it possible to change the parent of dg from the method "otherMethod"?

Assuming you're not calling otherMethod within FromFile_Click, you need to make it an instance variable - like your TabControl is, except hopefully not public. I'm assuming otherMethod is actually meant to handle an event of some kind, rather than being called directly.
Now this is assuming that you want one DataGrid per instance of MainWindow, associated with that window. If that's not the case, you'd need to provide more information.

You have to pass it as a parameter to the other method otherMethod or make it a member variable.

set the DataGrid dg as a property instead of declaring inside the FromFile_click.
This way when you assign "dg" it will work from any other method (few restrictions apply)

Related

Pass data from User Control A to User Control B within a Form [duplicate]

This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 2 years ago.
To masters out there, I'm having problem with passing values 2 user controls within a form. I have usercontrol A which has combobox and a button and control B that has a datagridview. Now I want to display the data in User Control B which is in the datagridview. How can I pass the data from UCA to UCB?
Here's the data I want to pass:
So in User Control A when I clicked the button named Generate, it will fill the datagridview in User Control B with the data generated in the GetConvo() below.
public DataTable GetConvo() {
DataTable table = new DataTable();
table.Columns.Add("ConvoUser", typeof(Object));
table.Columns.Add("Message", typeof(Object));
table.Columns.Add("Date", typeof(Object));
var _data = from data in User.GetMatchConvo(comboBox3.SelectedValue.ToString())
select new {
convoUser = data.actor_id,
convoMessage = data.message,
convoDate = data.creation_timestamp
};
foreach (var data in _data) {
table.Rows.Add(data.convoUser, data.convoMessage, data.convoDate);
}
//dataGridView1.AllowUserToAddRows = false;
//dataGridView1.AllowUserToDeleteRows = false;
return table;
}
private UserInterface User = new UserData();
UserControlA knows/should know UserControlB?
Then create a property of type of UserControlB in UserControlA, then whenever you want to pass data to UserControlB, use the instance which you have in UserControlB property.
Which is which? Right, Maybe the BindingNavigator and BindingSource example is a bit clearer:
public class BindingNavigator
{
Public BindingSource BindingSource { get; set; }
public int Position
{
get {return BindingSource?.Position ?? -1};
set {if(BindingSource!=null) BindingSource.Position = value;}
}
}
Then when you dropped an instance of the BindingNavigator and an instance of the BindingSource on the form, set BindingSource property of the BindingNavigator to bindingSource1.
UserControlA doesn't/shouldn't know UserControlB?
Use events. It's the most natural way. Every day you are using it, like TextChanged, SelectedIndexChanged, and so on. Time to create one for your user control.
In fact you need to raise event in UserControlA, then on the form, when you dropped an instance of UserControlA and an instance of UserComtrolB, handle UserControlA event and set UserControlB property.
To make it a bit clearer, again with BindingNavigator and BindingSource:
public class BindingNavigator
{
public event EventHanlder MovingNext;
public void MoveToNextRecord()
{
MovingNext?.Invoke(this, EventArgs.Empty);
}
}
Then when you dropped an instance of the BindingNavigator and an instance of the BindingSource on the form, handle MovingNext event of bindingNavigator1 and set position of the bindingSource1:
bindingNavigator1.MovingNext += (obj, args) => {
bindingSource1.Position +=1;
};
Want to learn more about events? Take a look at the following documentations:
Handling and raising events
Standard .NET event pattern
you can create a static variable in usercontrol and pass data to this variable
in UserControl A or B Create a variable
public static string info = string.empty;
and before you open usercontrol you must pass data to variable
UsercontrolA.info = "hello";
new UsercontrolA();
UPDATE
create a static instance of usercontrol in UsercontrolA
public static internal UsercontrolA uc;
now in you ctor
public UsercontrolA(){
InitializeComponent();
uc = this;
}
You now need a function to perform the display operation
public void showData(){
// your display codes
messagebox.show(info);
}
And at the end, after you click button, also call the display function.
UsercontrolA.info = "hello";
new UsercontrolA();
UsercontrolA.us.showData();
I didn't test the codes but it definitely should work

Execute method on tabpage created in code

I have searched but cannot locate this problem.
On form 1 in code, I create a TabPage with a usercontrol in it and then add the TabPage to form1.TabControl and call public method LoadData on the usercontrol.
Problem: I need to reload the data when the new tabpage is activated or gains focus. If I did not create the tabpage in code, I could simply use TabControl's selectedIndex change event, but it needs to be created in code.
How can I do this? Form 1:
private void CreateNewTab()
{
TabPage tp1 = new TabPage();
tp1.Text = "HSV";
tp1.Name = "tpHSV";
if (tabContMain.TabPages.ContainsKey(tp1.Name) == false)
{
HSVControl hsvc = new HSVControl();
hsvc.Dock = DockStyle.Fill;
hsvc.LoadData();
tp1.Controls.Add(hsvc);
tabContMain.TabPages.Add(tp1);
}
}
====EDIT===============
Thanks for the comments. Let me try to explain my problem better. The selectedIndex change event works fine. I can access the tab by it's text or name. The problem is calling the hsvc.LoadData() method. I need to recall this method when the tab containing hsvc user control is clicked. The LoadData() is public, but I cannot find a way to access it in Form1 (which holds the selectedIndex change event). I need a reference to hsvc control.
I added a property to the Form1 class like this:
private UserControl mControl;
then assigning it:
HSVControl hsvc = new HSVControl();
hsvc.Dock = DockStyle.Fill;
hsvc.LoadData();
mControl=hsvc;
Then calling it in SelectedIndex change event, but it is still not visible there.
Ok, thanks again for the help. The solution was kind of staring me in the face. I'm not sure it's the best, but this worked very well.
Created interface:
public interface IControlBase
{
void LoadData();
}
Had UserControl implement interface:
HSVControl : UserControl,IControlBase
and having the existing LoadData() method on the usercontrol.
change
private UserControl mControl;
to
private IControlBase mControl;
Then in SelectedIndex change:
mControl.LoadData();
TabControl Has a property called SelectedTab. use that property like:
private void CreateNewTab()
{
TabPage tp1 = new TabPage();
tp1.Text = "HSV";
tp1.Name = "tpHSV";
if (tabContMain.TabPages.ContainsKey(tp1.Name) == false)
{
HSVControl hsvc = new HSVControl();
hsvc.Dock = DockStyle.Fill;
hsvc.LoadData();
tp1.Controls.Add(hsvc);
tabContMain.TabPages.Add(tp1);
tabContMain.SelectedTab = tp1;
}
}
In that last line, It makes the TabControl to call its SelectedIndexChanged event. Then call LoadData event in this event:
private void TabControl_SelectedIndexChangedEvent(object sender, EventArgs e)
{
//So Because Hsvc is a public field. I call its method here:
if(TabControl.SelectedTab.Name = "My Desired Tab";
{
hsvc.LoadData();
}
}

Control changing control on other UserControl

I have a User Control that contains a combobox/drop down list. This user control is used multiple times and added dynamically to a panel. When I change the value of the combobox on one user control, it changes the rest? Does anyone know how to sort this?
So to clarify. When I change the value in the combobox of the top usercontrol (7002), it will change the second user controls combobox value to whatever I selected.
Thanks!
Code for adding the controls;
foreach (Common.UserDTO UDTO in BLL.User.GetAllUsers())
{
Admin_UserControls.UserBar UB = new Admin_UserControls.UserBar(UDTO);
UB.Location = new Point(0, int.Equals(pnlUserBlock.Controls.Count, 0) ? 0 : pnlUserBlock.Controls[pnlUserBlock.Controls.Count - 1].Bottom);
pnlUserBlock.Controls.Add(UB);
}
constructor/load events:
private Common.UserDTO UDTO;
public UserBar(Common.UserDTO UDTO)
{
InitializeComponent();
/* Store the passed in UserDTO */
this.UDTO = UDTO;
}
private void UserBar_Load(object sender, EventArgs e)
{
/* Setup the Drop down list */
cbRanks.DataSource = Common.Helper.GetRanksDT();
cbRanks.DisplayMember = "Rank";
cbRanks.ValueMember = "ID";
/* Setup the users */
lblUsername.Text = UDTO.Username;
cbRanks.SelectedValue = UDTO.RankID;
}
Put the above comment into an answer should others have the same issue in future.
Each instance of the UserControl that is created is bound to the same DataSet giving you this result.
Caused by the line:
cbRanks.DataSource = Common.Helper.GetRanksDT();
To resolve this simply declare a new instance each time the UserControl is created, see this post that discusses a few methods.

How to Give back a DataGridView in Winforms

So, I have a project in which I allow editing of a DatagridView in a separate Form. I pass in the DatagridView object and its parent container to the constructor of the new Form.
This works well and I can edit the grid that way. But when I try to give it back by changing its parent back to the original form, I get this error :
Cannot convert type 'System.Windows.Forms.MenuItem' to 'System.Windows.Forms.Control'
Now both MenuItem, and Manual Entry directly inherit from Form.
Here is my code that takes the DataGridView from the original form (which works correctly)
public partial class ManualEntry : Form
{
private Data d;
DataGridView DataView;
MenuItem mi;
public ManualEntry(DataGridView ExcelDisplay, Data d, MenuItem menuItem)
{
InitializeComponent();
//Take the Datagridview from the MenuItem.
DataView = ExcelDisplay;
DataView.Parent = this;
mi = menuItem;
this.d = d;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(15, 76);
this.DataView.Size = new System.Drawing.Size(237, 211);
this.DataView.TabIndex = 5;
this.DataView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataView_CellContentClick);
}
Now here is me trying to give it back. and of course it produces the error above.
private void FinishButton_Click(object sender, EventArgs e)
{
//move the datagridview back to the original form and give its old size,shape, and position back.
DataView.Parent = mi;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(12, 167);
this.DataView.Name = "ExcelDisplay";
this.DataView.Size = new System.Drawing.Size(250, 256);
this.DataView.TabIndex = 7;
this.Close();
}
I have also tried casting which does not work either.
DataView.Parent = (System.Windows.Forms.Control)mi;
Update
This shows that MenuItem is a Form as well.
public partial class MenuItem : Form
{
This shows that MenuItem is a Form as well.
Well, you have not convinced the compiler. You can tell from the error message that it thinks that your "mi" variable is a System.Windows.Forms.MenuItem. Do not use .NET class names for your own types, that just makes your life harder to troubleshoot bugs like this. Don't use variable names like "d" either. Choosing good names is a Very Important programmer's job.
The proper way is to preserve the control's Parent property so you can set it back. Roughly:
public partial class ManualEntry : Form
{
private Data DataViewData;
private DataGridView DataView;
private Point DataViewLocation;
private Control DataViewParent;
public ManualEntry(DataGridView ExcelDisplay, Data data)
{
InitializeComponent();
this.DataViewData = data;
this.DataView = ExcelDisplay;
this.DataViewLocation = ExcelDisplay.Location;
this.DataViewParent = ExcelDisplay.Parent;
this.DataView.Parent = this;
// etc...
}
protected override void OnFormClosing(FormClosingEventArgs e) {
base.OnFormClosing(e);
if (!e.Cancel) {
DataView.Parent = this.DataViewParent;
DataView.Location = this.DataViewLocation;
// etc..
}
}
}

Adding Items to a ListBox

I have a WPF main window, which contains a toolbar with buttons and a tabcontrol that is displaying a page with a listbox. The page is hosted on a frame, and the frame is set on the tab I selected.
When I click on a button on my toolbar, a new window pops up with a textbox and a submit button. When I press the submit button, I want to insert the textbox contents into the listbox that's on the main window. However, nothing displays in the listbox. I tried listbox.Items.Add() but it still won't display.
public partial class AddNewCamper : Window
{
public AddNewCamper()
{
InitializeComponent();
}
private void btnNewSubmit_Click(object sender, RoutedEventArgs e)
{
CampersPage c;
// Converting string to int b/c thats what camper() takes in.
int NewAge = Convert.ToInt16(txtNewAge.Text);
int NewGrade = Convert.ToInt16(txtNewGrade.Text);
// Create a new person
Camper person = new Camper(NewAge, NewGrade, txtNewFirstName.Text);
txtNewFirstName.Text = person.getName();
// Trying to add the first name of the person to display on the listbox of another window.
c.testListBox.Items.Add(txtNewFirstName.Text);
}
You can follow any of the following approaches. But based on your comments I guess solution 3 suits you.
1) Try initializing c first. You can't use an object without allocating memory for it.
2) If you want to use the same object, use the reference of the object created in the MainWindow
in the required class.
something like this should work:
CampersPage c = [reference to CampersPage object in MainWindow]
then add items to your listbox
3) If you want to use the listbox object, make your CampersPage Class static.
Making it static would not require you to initialize your class explicitly.
public static CampersPage {
// do something here
}
Make sure that you declare your listbox in CampersPage as public.
Then in the class requiring your listbox defined in CampersPage, do the following
CampersPage.testListBox.Items.Add(txtNewFirstName.Text);
4) If the classes are in the same namespace, you can declare listbox as a global public property and access it from rest of the classes in the same namespace.

Categories

Resources