Data from parent to dialog - c#

I have a parent form and a dialog. I need to pass info from the parent to the dialog
Here's what I have:
private void Item_Click(object sender, EventArgs e)
{
DialogResult result = DialogResult.OK;
DlgGraphOptions _frmDlgGraphOptions = new DlgGraphOptions();
_frmDlgGraphOptions.m_SerOpts = theDGroup.m_SerOpts;
_frmDlgGraphOptions.ShowDialog(this);
if (result == DialogResult.OK)
{
// Save the revised options to the Data Group
theDGroup.m_SerOpts = _frmDlgGraphOptions.m_SerOpts;
}
In DlgGraphOptions(child/dialog) form, I have intialitzed
public partial class DlgGraphOptions : Form
{
public GraphOpts_t m_SerOpts = new GraphOpts_t();
}
private void InitSettings(int idxSeries)
{
m_nMaxPts = m_SerOpts.GetMaxPts(idxSeries);
}
So I need to pass theDGroup.m_SerOpts from parent to the dialog,so I have done
_frmDlgGraphOptions.m_SerOpts = theDGroup.m_SerOpts;
in the parent. Now in the child:
public GraphOpts_t m_SerOpts = new GraphOpts_t;
This seems to be wrong. I don't want to be reinitializing it.

I think you should change your code in this way:
First, in the DlgGraphOptions form, change the constructor of DlgGraphOptions
// Force the caller to pass a GraphOpts_t
// Check if it is a valid instance or create one as new
public partial class DlgGraphOptions(GraphOpts_t input ) : Form
{
m_SerOpts = (input == null ? new GraphOpts_t() : input);
}
then create a public property with only the getter returning the internal GraphOpts
public GraphOpts_t Options
{
get{ return m_SerOpts; }
}
then, in the calling form, change uour code
// Pass the m_setOpts from theDGroup
DlgGraphOptions _frmDlgGraphOptions = new DlgGraphOptions(theDGroup.m_SerOpts);
if(DialogResult.OK == _frmDlgGraphOptions.ShowDialog(this))
{
// Save the revised (or new) options to theDGroup
theDGroup.m_SerOpts = _frmDlgGraphOptions.Options;
}
This approach will force the user of your dialog to pass an initialization value or null.
However your InitSettings will work with a initialized value and you don't have initialized two times your options instance.
(Actually there isn't a big improvement from your code, but I think it is a better approach)

Your child class should probably have the m_SerOpts as a property:
public partial class DlgGraphOptions : Form
{
public GraphOpts_t m_SerOpts { get; set; }
}
Your click event can probably be cleaned up like this:
private void Item_Click(object sender, EventArgs e)
{
using (DlgGraphOptions _frmDlgGraphOptions = new DlgGraphOptions()) {
_frmDlgGraphOptions.m_SerOpts = theDGroup.m_SerOpts;
if (_frmDlgGraphOptions.ShowDialog(this) == DialogResult.OK)
{
// Save the revised options to the Data Group
theDGroup.m_SerOpts = _frmDlgGraphOptions.m_SerOpts;
}
}
}
where in your DlgGraphOptions form, you need to set the form's DialogResult property in the OK or Save button event.
You could also just pass m_SerOpts object through the constructor:
public partial class DlgGraphOptions : Form
{
public GraphOpts_t m_SerOpts { get; }
public DlgGraphOptions(GraphOpts_t serOpts) {
InitializeComponents();
m_SerOpts = serOpts;
}
}

Related

How to return to the calling method after calling a windows Form in c#?

I have a method, where I call a new Windows Form in Class A. And in the new Form, I use a Dropdown menu and store the selected Item from the Dropdown in a variable, called selectedItem.Now I have to access this selectedItem in Class A. I use the following code.
public class A
{
public method callingmethod()
{
ExceptionForm expform = new ExceptionForm();
expform.Show();
string newexp = expobj.selectedexception;
}
}
And my code in New Form,
public partial class ExceptionForm : Form
{
public string selectedexception = string.Empty;
private void btnExpSubmit_Click(object sender, EventArgs e)
{
selectedexception = this.comboBox1.GetItemText(this.comboBox1.SelectedItem);
this.Close();
return;
}
}
Now After clicking on Submit button, I get the correct value in selectedItem, But I could not pass it to Class A. How to retun to Class A?
If you are ok with posting ExceptionForm over parent form by disabling it, go for ShowDialog. But, if you do not wish to disable parent for and continue popping ExceptionForm as a new and independent window, try eventing back to parent form. Here I show an example on how to do so:
public partial class ExceptionForm : Form
{
public delegate void SelectValueDelegate(string option);
public event SelectValueDelegate ValueSelected;
private void btnExpSubmit_Click(object sender, EventArgs e)
{
this.Close();
if (this.ValueSelected!= null)
{
this.ValueSelected(this.comboBox1.GetItemText(this.comboBox1.SelectedItem));
}
return;
}
}
And in calling class:
public class A
{
public method callingmethod()
{
ExceptionForm expform = new ExceptionForm();
expform.ValueSelected += ExceptionForm_ValueSelected;
expform.Show();
}
private void ExceptionForm_ValueSelected(string option)
{
string newexp = option;
// Do whatever you wanted to do next!
}
}
Use ShowDialog() method.
expform.ShowDialog();
string newexp = expobj.selectedexception;

Windows Form Application how return value form one form to other

I'm writing an application which will be storing film that i watched and I going to watch in future in XML file ( simple app only for training )
The main object which i use to store data in my app look like :
public class FilmDto : IFilmDto
{
public int FilmId { get; set; }
public string Name { get; set; }
public DateTime? WatchedDate { get; set; }
public int ParentId { get; set; }
public string ParentName { get; set; }
public FilmStatus FilmStatus { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
}
All the operation is perform in Service class. There are list of film as main data file.
The service class look this :
public class FilmService
{
private List<FilmDto> _films = new List<FilmDto>();
private FilmDao _filmDao = new FilmDao();
private FilmService()
{
_films = _filmDao.Load();
}
public static FilmService Inicialize()
{
return new FilmService();
}
public void Save()
{
_filmDao.Save(_films);
}
public List<FilmDto> GetFilmsByCriteria(FilmCriteriaDto criteria, bool withStatus)
{
if (withStatus)
{
return _films.Where(x => x.Category.Contains(criteria.Category)
&& x.SubCategory.Contains(criteria.SubCategory)
&& x.ParentName.Contains(criteria.ParentName)
&& x.Name.Contains(criteria.Name)
&& x.FilmStatus.Equals(criteria.FilmStatus)).ToList();
}
else
{
return _films.Where(x => x.Category.Contains(criteria.Category)
&& x.SubCategory.Contains(criteria.SubCategory)
&& x.ParentName.Contains(criteria.ParentName)
&& x.Name.Contains(criteria.Name)).ToList();
}
}
public StatisticDto GetFilmStatistic()
{
return new StatisticDto
{
TotalCount = _films.Count,
TotalToWatch = _films.Where(x => x.FilmStatus == FilmStatus.DoObejzenia).Count(),
TotalWatched = _films.Where(x => x.FilmStatus == FilmStatus.Obejzany).Count()
};
}
public List<string> GetAllParentName()
{
return _films.Select(x => x.ParentName).ToList();
}
public void Add(FilmDto film)
{
_films.add(film);
}
// Private Methods
private int GetNexID()
{
return _films.OrderByDescending(x => x.FilmId).FirstOrDefault().FilmId + 1;
}
}
Now its time to form which i use to resent data. The form use service instance and call method form service to get those data ( form have only display data and do not have any logic to transform it )
public partial class Form1 : Form
{
private FilmService _filmService
public Form1()
{
_filmService = FilmService.Inicialize();
InitializeComponent();
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
FillTable(new FilmCriteriaDto(), false);
}
private void FillTable(FilmCriteriaDto criteria,bool witchStatus)
{
List<FilmDto> films = _filmService.GetFilmsByCriteria(criteria,witchStatus);
foreach (FilmDto film in films)
{
dataGridView1.Rows.Add(film.Name,film.WatchedDate,film.ParentName,film.Category,film.SubCategory,film.FilmStatus);
}
}
private void statisticToolStripMenuItem_Click(object sender, EventArgs e)
{
StatisticDto stats = _filmService.GetFilmStatistic();
MessageBox.Show(string.Format("Total :{0}\nWatched {1}\nTo watch {2}"
, stats.TotalCount, stats.TotalWatched, stats.TotalToWatch), "Stats INFO",MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void addToolStripMenuItem_Click(object sender, EventArgs e)
{
...Call new form to add new film
}
}
To this moment everything is quite nice. But now i need to create new form ( Form2) which will have TexBox to insert new film data to my list in service. No i don't know ho to do this.
First i thought that i change private FilmService _filmService to public FilmService FilmService {get;set;}
And in form2 create constructor where I give Form1 object like public Form2(Form1 form) and make call it form Form1 like : Form2 form = new Form2(this) . In that case i have access to that service method but it will look like form.FilmService.Add which is not nice. In other way i can pass FilmService object as parameter but in that way Form1 will don't know change which Form2 make. I want to create method in Form2 which will be returning FilmDto object to Form1 when e.g i click buton in Form2 is there any way to do that ?
You can use different ways to do this.
The simplest is to use Dialogs. You can open your Form2 as fialog by call ShowDialog and then just read the property if result is OK. It's a general way to implement your behavior in WinForms.
private void addToolStripMenuItem_Click(object sender, EventArgs e)
{
// Show testDialog as a modal dialog and determine if DialogResult = OK.
if (form2.ShowDialog(this) == DialogResult.OK)
{
// Read the contents of testDialog's TextBox.
this.txtResult.Text = form2.TextBox1.Text;
}
}
Note that you must set DialogResult property in Form2 to DialogResult.OK if user click the button and DialogResult.Cancel in other way. It helps you to handle scenario when user has decided not to add new movie.
The other way is to use events. Declare new event in Form2 and subscribe Form1 to this event. Raise new event on button click and pass your data as a parameter of your event.
First of all you can make FilmService static or singleton.
Also you can find some examplex for your particular task here - Communicate between two windows forms in C#
In my Point of View, you should use MVP pattern - https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter
But probably it is overkill.

Cannot get selectedItem to textbox

I'm trying to get listbox selected item from one form 1 to display on textbox on form 2.
So far it's working partly.
The problem is that it only gets the selectedItem that was selected at the start of the application. If the user selects a new item, it still gets the one that was selected as default.
Form 1 MainForm:
public MainForm()
{
public string GetListBoxSelectedItem()
{
if (Animallst.SelectedItem != null) //Animallst is the listbox
{
return Animallst.SelectedItem.ToString();
return string.Empty;
}
}
private void foodbtn_Click(object sender, EventArgs e)
{
FoodRegister foodForm = new FoodRegister();
foodForm.Show();
}
}
Form 2 FoodRegister:
public partial class FoodRegister : Form
{
private RecipeManager m_foodmanager = new RecipeManager();
public FoodRegister()
{
InitializeComponent();
MainForm main = new MainForm();
Nametxt.Text = main.GetListBoxSelectedItem();
//My initializations
InitializeGUI();
}
}
These two lines are not at all doing what you want them to do. You're creating an entirely new instance of MainForm, which has nothing to do with the original instance. And so GetListBoxSelectedItem() doesn't do what you want either.
MainForm main = new MainForm();
Nametxt.Text = main.GetListBoxSelectedItem();
Instead, pass a reference to the original Form into the second Form:
public FoodRegister(MainForm main)
{
InitializeComponent();
Nametxt.Text = main.GetListBoxSelectedItem();
...
And then call it like this:
FoodRegister foodForm = new FoodRegister(this);
foodForm.Show();
A couple of things to mention:
The line return string.Empty is redundant. Because of the line above it, this line becomes unreachable
In your FoodRegister for, you create a new instance of your main form. This then wipes anything that the main form was holding - i.e. Animallst.SelectedItem.ToString();
An easy way to handle this is to set the value to a static variable - that way you won't have to create a new instance of the form to access it.
Main form:
public static string GetListBoxSelectedItem()
{
if (Animallst.SelectedItem != null) //Animallst is the listbox
{
return Animallst.SelectedItem.ToString();
}
else { return string.Empty(); }
}
Food Register:
public FoodRegister()
{
InitializeComponent();
MainForm.GetListBoxSelectedItem();
//My initializations
InitializeGUI();
}
Haven't played with WinForms in awhile but here goes
In Form 2
public partial class FoodRegister : Form
{
private RecipeManager m_foodmanager = new RecipeManager();
public FoodRegister()
{
InitializeComponent();
//My initializations
InitializeGUI();
}
public void SetText(string txt)
{
Nametxt.Text = txt;
}
}
In Form 1
public MainForm()
{
private readonly FoodRegister foodForm = new FoodRegister();
private void foodbtn_Click(object sender, EventArgs e)
{
foodForm.SetText(Animallst.SelectedItem == null ? "" : Animallst.SelectedItem.ToString());
foodForm.Show();
}
}
I replaced
GetListBoxSelectedItem()
with
Animallst.SelectedItem == null ? "" : Animallst.SelectedItem.ToString()

I need to access a form control from another class (C#)

On my form, I have one Panel container, named "panelShowList".
On my project, i added a new class, which look like this:
class myNewClass
{
private int newPanelPos = 30;
private const int spaceBetweenElements = 30;
private const int panelWidth = 90;
private const int panelHeight = 40;
private int elementPos = 0;
private ArrayList myPanels = new ArrayList() { };
// some irelevant methods
public void addElementPanels(Panel dataPanel, Panel nextPanel)
{
myPanels.Add(dataPanel);
myPanels.Add(nextPanel);
}
public void displayPanels()
{
foreach (Panel tmp in myPanels)
{
// here i'm stuck
// i need to do something like this :
// myMainForm.panelShowList.Controls.Add(tmp);
// of course this is wrong! but i need a method to acces that control
}
}
}
Basically, I need a way to add all Panels from my ArrayList on "panelShowList" control from my form.
I tried something like this:
public void displayPanels()
{
frmMain f = new frmMain();
foreach (Panel tmp in myPanels)
{
f.display(tmp);
// where display(Panel tmp) is a function in my Form, who access
// "panelShowList" control and add a new Panel
}
}
But it only works if i do this:
f.ShowDialog();
and another form is open.
Any suggestions will be appreciated.
Maybe a bit late, but by all means, here is another approach, that's still more clean than David's approach:
You should add an EventHandler in your MyNewClass. Then you can subscribe to that event from within your form.
public partial class Form1 : Form
{
private readonly MyNewClass _myNewClass;
public Form1()
{
InitializeComponent();
_myNewClass = new MyNewClass();
_myNewClass.DisplayPanelsInvoked += DisplayPanelsInvoked;
}
private void DisplayPanelsInvoked(object sender, DisplayPanelsEventArgs e)
{
var panels = e.Panels; // Add the panels somewhere on the UI ;)
}
}
internal class MyNewClass
{
private IList<Panel> _panels = new List<Panel>();
public void AddPanel(Panel panel)
{
_panels.Add(panel);
}
public void DisplayPanels()
{
OnDisplayPanels(new DisplayPanelsEventArgs(_panels));
}
protected virtual void OnDisplayPanels(DisplayPanelsEventArgs e)
{
EventHandler<DisplayPanelsEventArgs> handler = DisplayPanelsInvoked;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler<DisplayPanelsEventArgs> DisplayPanelsInvoked;
}
internal class DisplayPanelsEventArgs : EventArgs
{
public DisplayPanelsEventArgs(IList<Panel> panels)
{
Panels = panels;
}
public IList<Panel> Panels { get; private set; }
}
In my opinion it's a better solution, because you don't need to provide a reference of the form to the MyNewClass instance. So this approach reduces coupling, because only the form has a dependency to the MyNewClass.
If you always want to "update" the form whenever a panel is added, you could remove the DisplayPanels-method and shorten the code to this:
public partial class Form1 : Form
{
private readonly MyNewClass _myNewClass;
public Form1()
{
InitializeComponent();
_myNewClass = new MyNewClass();
_myNewClass.PanelAdded += PanelAdded;
}
private void PanelAdded(object sender, DisplayPanelsEventArgs e)
{
var panels = e.AllPanels; // Add the panels somewhere on the UI ;)
}
}
internal class MyNewClass
{
private IList<Panel> _panels = new List<Panel>();
public void AddPanel(Panel panel)
{
_panels.Add(panel);
OnPanelAdded(new DisplayPanelsEventArgs(_panels, panel)); // raise event, everytime a panel is added
}
protected virtual void OnPanelAdded(DisplayPanelsEventArgs e)
{
EventHandler<DisplayPanelsEventArgs> handler = PanelAdded;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler<DisplayPanelsEventArgs> PanelAdded;
}
internal class DisplayPanelsEventArgs : EventArgs
{
public DisplayPanelsEventArgs(IList<Panel> allPanels, Panel panelAddedLast)
{
AllPanels = allPanels;
PanelAddedLast = panelAddedLast;
}
public IList<Panel> AllPanels { get; private set; }
public Panel PanelAddedLast { get; private set; }
}
and another form is open
That's because you're creating an entirely new form:
frmMain f = new frmMain();
If you want to modify the state of an existing form, that code will need a reference to that form. There are a number of ways to do this. One could be to simply pass a reference to that method:
public void displayPanels(frmMain myMainForm)
{
foreach (Panel tmp in myPanels)
{
// myMainForm.panelShowList.Controls.Add(tmp);
// etc.
}
}
Then when your main form invokes that method, it supplies a reference to itself:
instanceOfNewClass.displayPanels(this);
Though, to be honest, it's not really clear what sort of structure you're going for here. If code is modifying a form then I imagine that code should be on that form. It can certainly be organized into a class, but perhaps that can be an inner class of that form since nothing else needs to know about it.
I'm also concerned that your implementation of myNewClass requires methods to be invoked in a specific order. Any given operation on an object should fully encapsulate the logic to complete that operation. Some of that initialization logic may belong in the constructor if the object isn't in a valid state until that logic is completed.
This is all a bit conjecture though, since the object structure isn't clear here.

Object loses data after initialization

I have these objects in my project:
SchedulerList
SchedulerListItem
SchedulerListItemDetails
each one is a win forms control, which are used in forms of my application. The SchedulerList holds SchedulerListItems and each item can have SchedulerListItemDetails.
my code goes as follows:
//creating my initial list form
FrmListTesting f = new FrmListTesting();
f.Show();
The form has only one button that has a hard-coded parameter for testing purposes, as well as a SchedulerList control taht will hold the list items.
When the button is clicked the form does the following:
private void button1_Click(object sender, EventArgs e)
{
var control = this.Controls[1] as SchedulerList;
var path = #"D:\Share\Countries.txt";
var sli = new SchedulerListItem(path);
control.AddItem(sli);
}
my SchedulerListItem constuctor goes as follows:
public SchedulerListItem(string path)
{
InitializeComponent();
this.Name = Path.GetFileNameWithoutExtension(path);
this.SourcePath = path;
this.DestinationPath = GetDestinationPath(path);
}
And the AddItem method is defined as:
public void AddItem(SchedulerListItem item)
{
this.flPanel.Controls.Add(item);
}
The add item method works as intended, displays all the data that was required and displays it in the UI. The list item has a button that brings up the details form as such:
//the form constructor
public FrmSchedulerItemDetails(SchedulerListItem item)
{
InitializeComponent();
this.detailsControl = new SchedulerListItemDetails(item, this);
}
//control constructor
public SchedulerListItemDetails(SchedulerListItem item, Form owner)
{
InitializeComponent();
this.SourcePath = item.SourcePath;
this.DestinationPath = item.DestinationPath;
this.OldFormat = item.OldFormat;
this.ExportToExcel = item.ExportToExcel;
this.owner = owner;
this.underlyingItem = item;
}
And now the problem. After the SchedulerListItemDetails constructor is called and the data "gets initialized", when i look at the data inside the object its set to default values. it seams that everything that I set after InitializeComponent(); gets ignored.
things that i have tried:
hard-coding the values to see if primitives get passed correctly
settings breakpoints on every InitializeComponent() method to see the stack trace associated with setting to default values
none of the methods show any results... I know that if i use a form directly instead of using a control within a from i can set the values the way i want to, but I'm very confused as to why this other method with controls doesn't work.
EDIT 1:
the code for SchedulerListItemDetails:
public partial class SchedulerListItemDetails : UserControl
{
public SchedulerListItemDetails(SchedulerListItem item, Form owner)
{
InitializeComponent();
this.SourcePath = item.SourcePath;
this.DestinationPath = item.DestinationPath;
this.OldFormat = item.OldFormat;
this.ExportToExcel = item.ExportToExcel;
this.owner = owner;
this.underlyingItem = item;
}
public SchedulerListItemDetails()
{
InitializeComponent();
}
private Form owner = null;
private SchedulerListItem underlyingItem;
public Boolean ExportToExcel
{
get
{
return this.cbxExcel.Checked;
}
set
{
this.cbxExcel.Checked = value;
}
}
public Boolean OldFormat
{
get
{
return this.cbxOldFormat.Checked;
}
set
{
this.cbxOldFormat.Checked = value;
}
}
public String DestinationPath
{
get
{
return this.tbxDestinationPath.Text;
}
set
{
this.tbxDestinationPath.Text = value;
}
}
public String SourcePath
{
get
{
return this.tbxSourcePath.Text;
}
set
{
this.tbxSourcePath.Text = value;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.owner.Close();
}
private void btnSave_Click(object sender, EventArgs e)
{
underlyingItem.SourcePath = this.SourcePath;
underlyingItem.DestinationPath = this.DestinationPath;
underlyingItem.OldFormat = this.OldFormat;
underlyingItem.ExportToExcel = this.ExportToExcel;
btnCancel_Click(sender, e);
}
}
I'll make an answer, because it should help you to solve your problem.
You have default (parameterless) constructor, which may be called and if it is called, then your constructor with parameters is not called.
Proper design would be something like
public partial class SchedulerListItemDetails : UserControl
{
public SchedulerListItemDetails()
{
InitializeComponent();
}
public SchedulerListItemDetails(SchedulerListItem item, Form owner): this()
{
this.SourcePath = item.SourcePath;
...
}
}
Notice this(), this ensure what parameterless constructor is called before (and InitializeComponent() as well, no need to duplicate it in another constructor).
Back to your problem. In your case it's like this
public partial class SchedulerListItemDetails : UserControl
{
public SchedulerListItemDetails()
{
InitializeComponent();
}
public SchedulerListItemDetails(SchedulerListItem item, Form owner)
{
InitializeComponent();
this.SourcePath = item.SourcePath;
...
}
}
Only one constructor can be called. So if you put breakpoint in parameterless one and it's triggered, then you have problems. Because you create somewhere SchedulerListItemDetails without setting it's properties (they stay default).
More likely problem is that you create new instance of that object (either before or after constructing proper, if your code ever construct such object) and that instance is what you inspect later.
So after i got a quick course of how win forms work i figured out what the problem was.
my code that i thought was enough is:
public FrmSchedulerItemDetails(SchedulerListItem item)
{
InitializeComponent();
this.DetailsControl = new SchedulerListItemDetails(item, this);
}
public SchedulerListItemDetails DetailsControl
{
get
{
return this.detailsControl;
}
set
{
this.detailsControl = value;
}
}
the this.detailsControl is the control im trying to setup, but as i have learned the correct way of replacing a component for a new one is:
public FrmSchedulerItemDetails(SchedulerListItem item)
{
InitializeComponent();
this.DetailsControl = new SchedulerListItemDetails(item, this);
}
public SchedulerListItemDetails DetailsControl
{
get
{
return this.detailsControl;
}
set
{
this.Controls.Remove(this.detailsControl);
this.detailsControl = value;
this.Controls.Add(this.detailsControl);
}
}
Feel kinda silly now :).

Categories