refresh after .showDialog and show items in list - c# .NET - c#

Currently in my program a user opens form 1 to create a new instance of a class and it is then saved to a list. After form 1 closes I would like the main form to reload and show the updated list on the screen. I am having trouble figuring out how to refresh the main navigation and how I would get the list to show on the form.
MainNaviagation
public partial class MainNavigation : Form
{
private Model m_modelObj;
public MainNavigation(Model modelObj)
{
InitializeComponent();
m_modelObj = modelObj;
m_modelObj.ChocolateAdded += m_modelObj_ChocolateAdded;
}
void m_modelObj_ChocolateAdded(Chocolate newChocolate)
{
//whole list of chocolates
List<Chocolate> chocolateList = m_modelObj.ChocolateList;
}
private void button1_Click(object sender, EventArgs e)
{
string candy = comboBox1.SelectedItem.ToString();
Form1 aForm1 = new Form1(textBox1.Text, candy, m_modelObj);
aForm1.ShowDialog();
}
}
Model Class:
{
public delegate void ChocolateAddedEventHander(Chocolate newChocolate);
public class Model
{
public event ChocolateAddedEventHander ChocolateAdded;
public List<Chocolate> ChocolateList = new List<Chocolate>();
public void AddChocolateInList(Chocolate chocolate)
{
ChocolateList.Add(chocolate);
if (ChocolateAdded != null)
ChocolateAdded(chocolate);
}
}
form1
public partial class Form1 : Form
{
Model m_model;
public Form1(string name, string candy, Model modelObj)
{
InitializeComponent();
m_model = modelObj;
string str = name + " selected : ";
label1.Text = str;
}
private void button1_Click(object sender, EventArgs e)
{
Chocolate newChocolate = new Chocolate(comboBoxChocolateSelection.SelectedItem.ToString(), 12.5, true, 2);
m_model.AddChocolateInList(newChocolate);
this.Close();
}
}
chocolates
public class Chocolate
{
#region Fields
public string flavor;
public double cost;
public bool giftWrap;
public int quantity;
#endregion End of Fields
#region Constructors
public Chocolate(string flavor, double cost, bool giftWrap, int quantity)
{
this.flavor = flavor;
this.cost = cost;
this.giftWrap = giftWrap;
this.quantity = quantity;
}
#endregion End of Constructors
}

Related

How to start an event changed from a INotifyPropertyChanged

I have two windows. In the first window I would like to start the second window with some preference values (e. g. "MaxWords"). The second window holds a class with an interface for INotifyPropertyChanged. This works as expected...
public partial class PreviewPreferences : Window
{
public PreviewPreferences()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel
{
public Preferences preferences { get; private set; }
public ViewModel()
{
preferences = new Preferences();
}
}
public class Preferences : INotifyPropertyChanged
{
private int _maxWords = 10;
/// <summary>
/// Default constructor
/// </summary>
public Preferences() { }
/// <summary>
/// Max words
/// </summary>
public int MaxWords
{
get { return this._maxWords; }
set { this._maxWords = value; this.OnPropertyChanged("MaxWords"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
The second window should updating the first window and adds some user controls to the grid. The question is not how to add the controls... it is more how to raise the event from the preference class that the value MaxWords is changed?
private void button_preview_preferences_Click(object sender, RoutedEventArgs e)
{
PreviewPreferences previewPreferences = new PreviewPreferences();
previewPreferences.Show();
Preferences preferences = new Preferences();
preferences.PropertyChanged += HandleChangedPreferences;
}
private void HandleChangedPreferences(object sender, PropertyChangedEventArgs e)
{
// this will never be raised
for (int i = 0; i < MaxWords; i++)
{
...
}
}
you have two instance of Preferences in button_preview_preferences_Click method. The first and important one (the one that changes) is hidden in PreviewPreferences DataContext:
private void button_preview_preferences_Click(object sender, RoutedEventArgs e)
{
var previewPreferences = new PreviewPreferences();
var preferences = (previewPreferences.DataContext as ViewModel).preferences;
preferences.PropertyChanged += HandleChangedPreferences;
previewPreferences.Show();
}
I suggest to invert the logic - create preferences outside ViewModel, and create ViewModel outside PreviewPreferences view:
public partial class PreviewPreferences : Window
{
public PreviewPreferences()
{
InitializeComponent();
}
}
public class ViewModel
{
public Preferences preferences { get; private set; }
public ViewModel(Preferences p)
{
preferences = p;
}
}
private void button_preview_preferences_Click(object sender, RoutedEventArgs e)
{
var preferences = new Preferences();
preferences.PropertyChanged += HandleChangedPreferences;
var previewPreferences = new PreviewPreferences();
previewPreferences.DataContext = new ViewModel(preferences);
previewPreferences.Show();
}

C# Calling a main form method via other class

I have this project where i contain all my panel instances in my main form.
PanelA aPanelA = new PanelA;
PanelB aPanelB = new PanelB;
This is the form where the program.cs load when it starts.
Because i would like to have a centralize place for each panel calling one another method within them hence i declare them in main. In main, i also make some methods doing certain function in these panel since they are declare in main.
void setPanelA (int iNumber){...}
void setPanelB (string strString){...}
The problem is how would a widget in PanelA call the method setPanelB() via main?
Main.setPanelB("Hello World);
I know i can declare PanelA and PanelB as static. But is this the only way to do it? Because if i declare static to both Panel, i will need to declare some instances within Panel as static too..
I also do not wish to declare PanelA in PanelB or via versa because i could have many type of panels and this would make my code very untidy.
*Edited I had add a sample code here
namespace TestPanel
{
public partial class Form1 : Form
{
PanelA aPanelA = new PanelA();
PanelB aPanelB = new PanelB();
//IT IS POSSIBLE TO HAVE TENS OF DIFFERENT TYPE OF PANEL
public Form1()
{
InitializeComponent();
}
//CENTRAL LOCATION WHERE ALL PANEL COULD CALL EACH OTHER METHOD
public void setPanelACentral(int iNew)
{
aPanelA.setPanelA(iNew);
}
public void setPanelBCentral(string strNew)
{
aPanelB.setPanelB(strNew);
}
}
public class PanelA
{
int i = 0;
public void setPanelA(int iNew)
{
i = iNew;
}
}
public class PanelB
{
string str = "";
public void setPanelB(string strNew)
{
str = strNew;
}
//PROBLEM HERE HOW TO ACCESS MAIN setPanelACentral
public void changePanelA()
{
int i = 1000;
Form1.setPanelACentral(i); //<- This the part where i am asking
}
}
}
The following code demonstrates adding Events to both your Panel types and Form1. By doing this, you can raise an event in your Panel that Form1 will have registered to handle.
public partial class Form1 : Form
{
protected EventHandler<PanelEventArg> OnSetPanelA = new EventHandler<PanelEventArg>((sender, e) => { }); //stub
protected EventHandler<PanelEventArg> OnSetPanelB = new EventHandler<PanelEventArg>((sender, e) => { }); //stub
protected List<PanelBase> panels;
public Form1() : base()
{
panels = new List<PanelBase>
{
new PanelA(),
new PanelB()
};
foreach (var panel in panels)
{
OnSetPanelA += panel.OnSetPanel;
OnSetPanelB += panel.OnSetPanel;
panel.OnSomeEvent += Form1_OnSomeEvent;
}
foreach (var panel in panels.OfType<PanelB>())
{
panel.OnChangePanelA += Form1_OnChangePanelA;
}
InitializeComponent();
}
protected void SetPanelA(int iNew)
{
foreach (var panel in panels.OfType<PanelA>())
{
panel.SetPanelA(iNew);
OnSetPanelA(this, new PanelEventArg
{
Panel = panel
});
}
}
protected void SetPanelB(string strNew)
{
foreach (var panel in panels.OfType<PanelB>())
{
panel.SetPanelB(strNew);
OnSetPanelA(this, new PanelEventArg
{
Panel = panel
});
}
}
protected void Form1_OnSomeEvent(object sender, EventArgs e)
{
// handles events raised by the panel.
}
protected void Form1_OnChangePanelA(object sender, int iNew)
{
SetPanelA(iNew);
}
}
Helper Types I'm including: PanelEventArg, PanelBase
public class PanelEventArg : EventArgs
{
public PanelBase Panel { get; set; }
}
public class PanelBase //: Panel
{
public EventHandler OnSomeEvent = new EventHandler((sender, e) => { }); //stub;
public void OnSetPanel(object sender, PanelEventArg e)
{
if (!Equals(e.Panel, this))
{
//the panel being set is not this panel instance
}
}
}
Declaring PanelA and PanelB, with inheritance and new Event for PanelB
public class PanelA : PanelBase
{
int i = 0;
public void SetPanelA(int iNew)
{
i = iNew;
}
}
public class PanelB : PanelBase
{
public EventHandler<int> OnChangePanelA = new EventHandler<int>((sender, e) => { }); //stub
string str = "";
public void SetPanelB(string strNew)
{
str = strNew;
}
//PROBLEM HERE HOW TO ACCESS MAIN setPanelACentral
public void ChangePanelA()
{
OnChangePanelA(this, 1000);
}
}

Data from form1 listbox to form2 textbox

The goal of the program assignment I'm working on requires me to fill a listbox with items taken from a data file, and then allowing the user to modify parts of the selected item. To do this, I need assistance in figuring out how to pass part of a listbox's selected item in one form to a textbox in another form.
Here's the coding I have for the first form in my program:
public partial class Form1 : Form
{
const char DELIM = '\\';
const string FILENAME = #"C:\Visual Studio 2015\Data Files\Training Workshops data";
string recordIn;
string[] Fields;
static FileStream file = new FileStream(FILENAME, FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(file);
public int X;
public Form1()
{
InitializeComponent();
}
public class Workshop
{
public string title { get; set; }
public int days { get; set; }
public string categrory { get; set; }
public double cost { get; set; }
public string[] categrorynames =
{
"Application Development",
"Databases",
"Networking",
"System Administration"
};
}
Workshop shop = new Workshop();
private void button1_Click(object sender, EventArgs e)
{
Form2 secondForm = new Form2();
secondForm.Show();
}
private void PopulateList(string filePath)
{
while(recordIn != null)
{
try
{
recordIn = reader.ReadLine();
Fields = recordIn.Split(DELIM);
X = Convert.ToInt32(Fields[0]);
shop.categrory = shop.categrorynames[X];
shop.days = Convert.ToInt32(Fields[1]);
shop.title = Fields[3];
shop.cost = Convert.ToDouble(Fields[2]);
}
catch (Exception A)
{
if (X < 0 && X > 3)
{
shop.categrory = "invalid";
}
if (shop.days != Convert.ToInt32(Fields[1]))
{
shop.days = 0;
}
if (shop.title != Fields[3])
{
shop.title = "invalid";
}
if (shop.cost != Convert.ToDouble(Fields[2]))
{
shop.cost = 0;
}
}
}
}
}
And below is a link to a screenshot of the second form:
http://i.stack.imgur.com/IRqVh.png
I need to transfer the shop.categrory data of form1's listbox's selected item to the second form's, and the shop.title, shop.days and shop.cost to the corresponding textbox's. From there I can make it so that whatever the user enters in the textboxes would change the data of the selected item when they press the "save and exit" button.
Any help would be appreciated, and if anyone notices an error in the coding I have now, please feel free to point them out.
Create a Parameterized constructor in form2 that accepts a String, and create it's instance in first form, and pass the value you want to pass to the second form:
private void button1_Click(object sender, EventArgs e)
{
Form2 secondForm = new Form2("DATA TO BE SENT");
secondForm.Show();
}
and in form2 Create a Constructor:
public Form2(string data)
{
InitializeComponent();
txtData.Text=data;
}

using an array in two different forms C#

I have a problem with arrays which are made from class; actually I can make an array from a class and in the first form I set the data in may array, but when I switch to my second form and create an object from my class, I find my array empty so I can't use the information witch I had entered into my array.
public partial class Form1 : Form
{
string _name;
string _department;
int _id;
int _count;
int counter = 0;
Mediator m = new Mediator();
Employee ee = new Employee();
public Form1()
{
InitializeComponent();
}
private void Add_to_Array_Click(object sender, EventArgs e)
{
_name = txtName.Text;
_department = txtDepartment.Text;
_id = int.Parse(txtID.Text);
_count = counter;
m.Set_Value(_name, _department, _id,_count);
counter++;
Exchange();
//-----------------------------------
txtDepartment.Text = "";
txtID.Text = "";
txtName.Text = "";
}
private void Search_Click(object sender, EventArgs e)
{
listBox1.Items.Add(m.array[0].E_Name);
listBox1.Items.Add(m.array[0].E_Department);
listBox1.Items.Add(m.array[0].E_ID.ToString());
//---------------------------------------------------
listBox1.Items.Add(m.array[1].E_Name);
listBox1.Items.Add(m.array[1].E_Department);
listBox1.Items.Add(m.array[1].E_ID.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
}
public partial class Form2 : Form
{
Mediator M;
public Form2()
{
InitializeComponent();
}
private void Show2_Click(object sender, EventArgs e)
{
listBox1.Items.Add(M.array[0].E_Name);
listBox1.Items.Add(M.array[0].E_Department);
listBox1.Items.Add(M.array[0].E_ID.ToString());
//---------------------------------------------------
listBox1.Items.Add(M.array[1].E_Name);
listBox1.Items.Add(M.array[1].E_Department);
listBox1.Items.Add(M.array[1].E_ID.ToString());
}
class Employee
{
string Name;
string Department;
int ID;
//**************************
public string E_Name
{
get { return Name; }
set { Name = value; }
}
public string E_Department
{
get { return Department; }
set { Department = value; }
}
public int E_ID
{
get { return ID; }
set { ID = value; }
}
}
class Mediator
{
public Employee[] array = new Employee[5];
public void Set_Value(string name,string department,int id,int count)
{
array[count] = new Employee();
array[count].E_Name = name;
array[count].E_Department = department;
array[count].E_ID = id;
}
}
I would strongly suggest that you don't make Mediator m static.
IMHO this is a hack and you don't want to get in the habit of effectively making global variables everywhere, it will come back to bite you as you progress through your career.
The better solution is to pass Form2 only the data it needs to work on.
I'm guessing Form2 only needs to display the list of Employees, so you should create a Property in Form2 as follows:
public Employee[] Employees {get; set;}
[If you need more than just the list of employees then you should rather have a property for the Mediator - public Mediator Mediator {get; set;} ]
You then need to send this data to the second form just before you show it:
Form2 f2 = new Form2();
f2.Employees = m.array;
f2.Show();
Because the data is sent by reference any changes you make in form2 will reflect in the objects stored in form1.
Another option is to structure your program using the MVC pattern. It's a little bit more advanced, but it's a great pattern to keep your winForms apps neat and tidy. If you are building a wizard style app then I would strongly suggest this approach.
As an aside note you can also clean up the code quite a bit by using a list instead of an array to store the employee data - this will also make the code more adaptable to larger numbers of employees in the future.
You can also use C#s automatic properties to reduce the amount of code you need to write. So your code can look like this this instead:
public partial class Form1 : Form
{
private Mediator _mediator = new Mediator();
public Form1()
{
InitializeComponent();
}
private void Add_to_Array_Click(object sender, EventArgs e)
{
var newEmployee = new Employee
{
Name = txtName.Text,
Department = txtDepartment.Text,
ID = int.Parse(txtID.Text)
};
_mediator.Employees.Add(newEmployee);
Exchange();
//-----------------------------------
txtDepartment.Text = "";
txtID.Text = "";
txtName.Text = "";
}
private void Search_Click(object sender, EventArgs e)
{
foreach (var employee in _mediator.Employees)
{
listBox1.Items.Add(employee.Name);
listBox1.Items.Add(employee.Department);
listBox1.Items.Add(employee.ID.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Employees = _mediator.Employees;
f2.Show();
}
}
public partial class Form2 : Form
{
public List<Employee> Employees { get; set; }
public Form2()
{
InitializeComponent();
}
private void Show2_Click(object sender, EventArgs e)
{
foreach (var employee in Employees)
{
listBox1.Items.Add(employee.Name);
listBox1.Items.Add(employee.Department);
listBox1.Items.Add(employee.ID.ToString());
}
}
}
class Employee
{
public string Name { get; set; }
public string Department { get; set; }
public int ID { get; set; }
}
class Mediator
{
public List<Employee> Employees { get; private set; }
public Mediator()
{
Employees = new List<Employee>();
}
}
You need an instance of Form1 in Form2 to use the array you've created.
You have two options;
First one, you can store an instance of Form1 in a common class so you can reach it from Form2.
Second option; you need to pass reference of Form1 to your Form2 instance.
A quick fix for your problem would be to add the static keyword in your array definition. this will make it stateless and therefor there won't be a new (instance of the) array being created each time you access it.
You should also consider placing this array in some kind of a static class that will be in charge of handling this kind of global variables.
As for your edits, you have at least 2 options here: the first one is making the Mediator class and the array inside static; or create a property in your second form like public string [] SomeArray {get; set;} and pass the array to it after declaring the ... = new Form2(); and before calling the .Open()

mef - how to make recomposition work automatically?

I've been trying to get recomposition to work but no luck... I tried many times and many approches - with no luck... can anyone point out my mistake? I expect that after I drop a new .dll into plugins directory the Senders collection will be automatically repopulated with new stuff...
//exported classes
[Export(typeof(ISender))]
public class SMTP : ISender
{
public string Name
{
get { return "SMTP plugin"; }
}
public void Send(string msg)
{
}
}
[Export(typeof(ISender))]
public class Exchange : ISender
{
public string Name
{
get { return "Exchange plugin"; }
}
public void Send(string msg)
{
// .. blah
}
}
/---------------------------------------------------------------------
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private const string STR_Pugins = ".\\plugins";
[ImportMany(typeof(ISender), AllowRecomposition = true)]
private List<ISender> Senders;
private DirectoryCatalog d;
CompositionContainer c;
public MainWindow()
{
InitializeComponent();
listBox1.DisplayMemberPath = "Name";
ConfigPlugins();
bindSenders();
}
private void ConfigPlugins()
{
DirectoryInfo dir = new DirectoryInfo(STR_Pugins);
if (!dir.Exists)
dir.Create();
d = new DirectoryCatalog(STR_Pugins);
d.Changed += new EventHandler<ComposablePartCatalogChangeEventArgs>(d_Changed);
c = new CompositionContainer(d);
c.ExportsChanged += new EventHandler<ExportsChangeEventArgs>(c_ExportsChanged);
c.ComposeParts(this);
}
void d_Changed(object sender, ComposablePartCatalogChangeEventArgs e)
{
bindSenders();
MessageBox.Show("d_Changed " + (Senders == null ? 0 : Senders.Count));
}
private void bindSenders()
{
listBox1.ItemsSource = Senders;
}
void c_ExportsChanged(object sender, ExportsChangeEventArgs e)
{
bindSenders();
MessageBox.Show("c_ExportsChanged "+ (Senders == null ? 0 : Senders.Count));
}
}
AFTER RESPONSE
ok, I've added the refresh, but still I don't get why the listbox won't populate with the new data...
public partial class MainWindow : Window
{
private const string STR_Pugins = ".\\plugins";
[ImportMany(typeof(ISender), AllowRecomposition = true)]
private List<ISender> Senders;
DirectoryCatalog d;
CompositionContainer c;
public MainWindow()
{
InitializeComponent();
listBox1.DisplayMemberPath = "Name";
ConfigPlugins();
bindSenders();
}
private void ConfigPlugins()
{
DirectoryInfo dir = new DirectoryInfo(STR_Pugins);
if (!dir.Exists)
dir.Create();
d = new DirectoryCatalog(STR_Pugins);
c = new CompositionContainer(d);
c.ComposeParts(this);
}
private void bindSenders()
{
label1.DataContext = Senders;
listBox1.ItemsSource = Senders;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
d.Refresh();
bindSenders();
}
}
You have to call Refresh yourself. If you want you can use a FileSystemWatcher object to get notified when the directory contents have changed.
It won't repopulate because when the field is updated, a brand new List is set to the field. The existing collection is not modified. You have to set it up as a property instead of a field (you can still make it protected or private), then when the "set" is called, you update the listBox1.ItemsSource and the label1.DataContext.

Categories

Resources