Hello i´m coding in C# and have a problem.
I have two Forms (Form1 and Form2), and the first form (Form1) contains a listbox and some labels like this:
Name: label1
Phone: label2
City: label3
And so on
And the second form (Form2) is a form were the user can fill in Name, Phone, city...
And when the user Press OK The name will only show up in the listbox in Form1, but i want to make a method when the user presses a name in the listbox the other information that the user typed in shall beacome visible in the labels.
So if the user opens Form2 and types in:
Name: John
Phone: 0011223344
City: New York
And then press ok the name John will beacome visible in the listbox but when the user selects John from the listbox the lables will show:
Name: John
Phone: 0011223344
City: New York.
Hope you can help me, thanks.
I'm assuming that your using strings to populate the ListBox here (you don't actually tell us how you are passing the data). Instead of passing a string from Form2 back to Form1, pass a data object:
class Person
{
string Name { get; set; }
string PhoneNumber { get; set; } // perhaps not best as a string
string City { get; set; }
}
Now expose a "Person" property from Form2:
class Form2
{
public Person Person
{
get { return new Person() { Name = txtName.Text, PhoneNumber = txtPhone.Text, City = txtCity.Text }; }
}
}
So, in Form1 you can use that property like so:
using( Form2 frm = new Form2() )
{
if( frm.ShowDialog() == DialogResult.OK )
{
Person p = frm.Person;
list.Items.Add( p.Name );
lblName.Text = p.Name;
lblPhone.Text = p.PhoneNumber;
lblName.City = p.City;
}
}
you have to write the code to update the lables in the SelectedIndexChanged event of the list box.May be some thing like this:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
form2.label1.text = getname(listBox1.SelectedItem.ToString());
form2.label2.text = getPhone(listBox1.SelectedItem.ToString());
form2.label3.text = getCity(listBox1.SelectedItem.ToString());
}
I'm not 100% certain I understand the layout on your form1, but it sounds like maybe you want some databinding and that might make your life easier.
If you had a class, say called Person, that had a Name, Phone, City property. Then rather than using a listbox, use a datagrid on your main form (styling it appropriately), and it can be bound to a List.
Then when you can use your labels to add new Person's to the datasource, but you can also select a person in the datagrid, and have your labels bounds to the columns, e.g.
this.lblName.Text = form1.datagrid.SelectedRows[0].Cell["Name"];
Doesn't directly answer your question but maybe a slightly nicer approach.
When the user clicks OK from Form2, you will have to retrieve the data they just entered and store it somewhere in Form1.
My advice would be to have a struct type called Person or something containing Name, Phone and City fields. Also, override the ToString method, and from that, simply return the Name field. Then you can add Person objects to your ListBox. Only the name will appear in the ListBox, and the SelectedItem property of the ListBox will return a Person struct, which will give you access all the information you need for the selected item.
Now all that's left is to handle the SelectedIndexChanged event, from which you can populate the labels with the data from the SelectedItem property.
Related
I have a very basic program to navigate to a network file, however, I want to navigate to certain folders depending on which one the user selects.
I have combo box 1 - County (Dropdown includes UK, Ireland, Spain, USA, India)
combo box 2 is generated depending on the selection from combo 1 (if UK is selected then London, Manchester or Liverpool can be selected, if USA is selected then the user has the option to select New York or San Francisco etc).
When the user selects the office, (London for example), I would like the file explorer to open at the London file share, or if they select New York, it would open at the New York file share.
Currently I have it hard coded to navigate to the correct network folder, but I' not sure how I would change it to navigate to the correct network file depending on the user selection.
private void btnNavigateToFolder_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start("explorer.exe", "\\\\London.xxx\\Finance");
}
These are some of the examples of the network folder names I would like to navigate to, depending on the user select for combo 2.
NewYork - \\NewYork.xxx\Finance
Liverpool- \\Liverpool.xxx\Finance
First, define a class to manage each ComboBox item. You must use a class with the Text to show in the combobox and all other information that you want to be available for each item. For example:
public class ComboBoxItem
{
public ComboBoxItem()
{
}
public ComboBoxItem(string text, string path)
{
this.Text = text;
this.Path = path;
}
public string Text { get; set; }
public string Path { get; set; }
public override string ToString()
{
return this.Text;
}
}
You can define ComboBoxCityItem and ComboBoxOfficeItem if they have different information but for your case I think we only need the Path part.
Add items to your ComboBox using previous class. You have 3 comboboxes but only use city and office to make the path (if I'm not wrong). So:
this.cityComboBox.Items.Add(new ComboBoxItem("London", "London.xxx"));
this.officeComboBox.Items.Add(new ComboBoxItem("Finance", "Finance"));
The text that you return in ToString method is the ComboBox text.
And now, you can make the path getting the selected items in the ComboBoxes:
private void btnNavigateToFolder_Click(object sender, EventArgs e)
{
var city = this.cityComboBox.SelectedItem as ComboBoxItem;
var office = this.officeComboBox.SelectedItem as ComboBoxItem;
if (city != null && office != null)
{
var path = $"\\\\{city.Path}\\{office.Path}";
System.Diagnostics.Process.Start("explorer.exe", path);
}
}
UPDATE
Knowing that you are starting, I can explain a bit more detailed.
The combobox is a control that contains objects, any type of object. You can insert into the combobox a string (is an object), but also a more complex class like ComboBoxItem. The combobox only show a string for each item: if you insert a ComboBoxItem instance, the combobox invoke ToString method to get the text to show in the control.
When you work with the items (Items, SelectedItem...), you know that these objects are ComboBoxItem instances. So you can do a cast and work with your class.
You can add items to a combobox from the designer, but these items are strings, not ComboBoxItem objects. If you look in the YourForm.designer.cs file, you can see how the designer adds the items. It's simply invoke Add or AddRange with the items. But you want use your own class (ComboBoxItem) so you can't use the designer. You can invoke the comboBox.Items.Add(...) in any method of your Form. If you are filling now in the designer, you can do with ComboBoxItem in the constructor. Remember delete the items in the designer or you'll have some items as string and other items as ComboBoxItem.
Before I begin, I have researched and can't seem to find anything. Note I am very new to UserControl so this might be why it's proven difficult.
I have a combobox in Form1 which when selected allows the user to change between a choice of 21 languages. I have created a UserControl that contains labels, buttons and checkboxes - adds to a form called Print.
If a user selected French, how would I then implement the UserControl to change language for ALL forms in my project?
UserControl:
I have used a get and set method here for a button. When the language is changed in Form1, I want this button (all elements really) to change.
using System.Windows.Forms;
namespace Print
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string LabelPreview
{
get
{
return Button_Preview.Text;
}
set
{
Button_Preview.Text = value;
}
}
}
}
Form1:
If string value English is selected in the combobox, call a method - here is where I would like to change language for other forms.
private void ComboBoxLang_SelectedIndexChanged(object sender, EventArgs e)
{
string selectedItem = this.comboBoxLang.GetItemText(this.comboBoxLang.SelectedItem);
if (selectedItem == Language.English)
{
ToEnglish();
}
}
private void ToEnglish()
{
// Cannot actually implement the UserControl, It can't find the method above.
// When I've tried to implement UserControl in Print, it can't seem to find it either.
// I've tried:
// Print.UserControl1.(_LabelPreview doesn't show_);
// ^ It might be the completely wrong thing to do so excuse me.
}
I'm so confused... Do I program in Print (where the UserControl is added) or/and Form1?! I don't want the design to appear in Form1, but just want to let the other forms know what language has been selected.
Note: I have been using Unicode when translating*
How to trigger application-wide language change I described here on your other question Everytime ComboBox is changed (using SelectedIndexChanged) display message in other forms, if opened, of new value
Now, to set controls... One way of doing it is to create Database of phrases with StringId in one table and the StringId, LanguageId, StringValue in another. You would create StringManager object, which will have method GetLanguageSpecificString(stringId, languageId). When language change is triggered, your controls will call GetLanguageSpecificString fro each label you display, etc.
So your data will be like
Table DisplayLanguage
LanguageId Int
LanguageName nvarchar
LanguageCulture varchar
//1, English, us-En
//2, French, fr-Ca
Table DisplayString
StringId Int
//1
//2
//3
Table DisplayStringValue
DisplayStringValueId int
StringId int
LanguageId int
StringValue nvarchar
//1, 1, 1, Person Name
//2, 1, 2, Nome de Persona(or whateever)
Create cache using
"Select * from DisplayStringValue where LanguageId = 1"
And then use Linq or something to select for each control its data from cache because you don't want to hit DB with these for each control
"Select StringValue from DisplayStringValue where StringId = 1 and LanguageId = 1"
Now, combine my other answer with this and you will see that if in your form you have
LanguageChangeObserver.LanguageChanged += MyObserverHandler;
private void MyObserverHandler(languageId)
{
_formLanguage = languageId;
// set your controls
lblFirstName.Text = GetLanguageSpecificString(5, languageId);
lblLastName.Text = GetLanguageSpecificString(6, languageId);
// loop through userControls and pass to them language id
}
It would be good idea if your user controls would derive from the single base class that you create and which has already SetNewLanguage Method, so you could do
foreach (var c in form.controls)
{
MyControlBase currControl = c as MyControlBase;
if (currControl != null) currControl.SetNewLanguage(languageId);
}
So I've come up with a solution that works for me! I've copied across from the Printer.cs form where I have used a parameter to represent the language chosen, initiated strTextBox to equal label1 and included an if statement to see if the language is English (also working with UserControl to get the value of labels etc.).
Printer
public Printer(string strTextBox)
{
InitializeComponent();
label1.Text = strTextBox;
if (label1.Text == Language.English)
{
UserControl111.Label_Option_Multi = "Please select an option:"; //Simple test
}
}
Form1
private void Print_Click(object sender, EventArgs e)
{
string selectedItem = this.ComboBox_Lang.GetItemText(this.ComboBox_Lang.SelectedItem);
Printer p = new Printer(selectedItem);
p.Show();
}
UserControl
public string Label_Option_Multi
{
get
{
return Label_Option.Text;
}
set
{
Label_Option.Text = value;
}
}
As a result, if I select English in Form1.s then open up Printer.cs, the label displays English and translates accordingly.
You have to do it same way as for any other control. Imagine you have created your TextBox and now want all your textboxes in the project on each form to do something.
Obviously, you have to get a list of such controls somehow. One approach is to use Application.Forms to iterate through everything. Other is to register your control (add to a list) every time when it's created or shown or what_you_need and de-register (remove from a list) otherwise.
I have Form1.cs which has two buttons say "ADD" and "EDIT".
Clicking "ADD" shows dialog Form2.cs.
Form2 has a TextBox and a ComboBox. Say we enter value "A" in textbox and select "A" from ComboBox.
Then close Form2.
Then when EDIT button is clicked on Form1, Form2 should show up with "A" in textbox and "A" selected in ComboBox.
This is a simple explanation. The real form I am using has around 10-12 different controls including combobox, checkbox, textbox etc.
My main doubt is where and how do we save these control values.
Is there a specific approach to this type of DialogBoxes that I am missing?
Create class, that would store values that you want to pass (let's call it Foo).
Form2 should then have a property. In the setter of the property, set controls:
public partial class Form2 : Form
{
private Foo _bar;
public Foo Bar
{
set
{
_bar = value;
//set your controls here
}
}
On Edit button, set property like this:
Form2 form2 = new Form2();
form2.Bar = bar; //bar contains values to edit
Then put a Save button on Form2, that would save values back from controls to this object.
For every control I would have a field in Foo class, eg. string for textboxes, bool for checkboxes and enum or int for comboboxes (where integer value would equal selected index).
Alternatively, you could use Dictionary class instead and have key and value pair for every control.
You can also have some enum, if your form looks or behaves differently in New and Edit mode.
Your Dialog Form should have a field containing the properties/fields you want, a copy a business object for example. Then you pass it or initialize it in your dialog constructor or Load, depending the behavior you want. From there you can create / initialize your controls.
If you want a built in system you may wanna take a look to the PropertyGrid (which you could embedded in a dialog (to fit your question))
Do you want to just load the last value user entered there?
For instance he writes "text" on the textbox and chooses "A" combobox it should be pre-selected next time you open it?
Edit: Then instead of closing it using Form.Close make it so that it hides. Form1.Hide. Next time it opens values are still saved. Unless application has been closed. In the other hand, users might click on the close button in the windows form. You can either make it "unclickable" throught proprieties or just configure it using events i think.
Create a method on Form2, where you will set values into textBox and select an item in comboBox. Call this method just after instantiating form2 and before showing it.
Example:
public Form2()
{
InitializeComponent();
comboBox1.Items.AddRange(new string[] { "a", "b", "c" });//fill comboBox your way on a loading time
}
public void UpdatingControls(string a, string b)
{
textBox1.Text = a;
comboBox1.SelectedText = b;
}
//on form2;
Form1 f2;
private void OpenForm2Button_Click(object sender, EventArgs e)
{
f2 = new Form2();
f2.UpdatingControls("a", "b"); //a will go into textBox, b will be choosen in comboBox
}
public Form2(string form1Textbox)
{
InitializeComponent();
form2Textbox.Text = form1Textbox;
}
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.
As a course project i'm building a form in c# which contains two user controls.
The first user control has a checkedlistbox and the second control has also a checkedlistbox when the first control checkedlistbox will contain list of people (male/female) and the second user control the checkedlistbox will have two options: male, female and when I click a button on the first control which says: "update friends" it's suppose to go to the second control and check if we selected male or female and according to that to update the checkedlistbox in the first user control with friends by gender type by what was selected on the second control.
Basically I want to raise an event every time the button on the first control selected then to get the data from the second control to the first control.
Is it possible to do so between two controls who are inside a form and are different controls?
Any help will be appriciated.
Thanks.
To do this "correctly," you would want to use something like the MVC architecture. It's definitely a lot more work initially to understand and implement but is very useful to know if you plan on doing any serious UI application development. Even if you don't go all the way with it, the concepts are useful to help design even "quick and dirty" applications.
Define your data model without thinking in terms of the UI, e.g.:
internal enum Gender
{
Male,
Female
}
internal class Person
{
public Gender Gender { get; set; }
public string Name { get; set; }
}
// . . .
// Populate the list of people
List<Person> allPeople = new List<Person>();
allPeople.Add(new Person() { Gender = Gender.Male, Name = "Xxx Yyy" });
allPeople.Add(new Person() { Gender = Gender.Female, Name = "Www Zzz" });
// . . .
For the view portion, you would typically use data binding on the UI controls so that the controls will automically reflect changes to the underlying data. However, this can get difficult especially if you are not using a database-like model (e.g. System.Data.DataSet). You may opt to "manually" update the data in the controls which might be fine in a small app.
The controller is the portion that uses the UI events and makes changes to the model, which may then be reflected as changes in the view.
internal class Controller
{
private Gender selectedGender;
private List<Person> allPeople;
private List<Person> friends;
public Controller(IEnumerable<Person> allPeople)
{
this.allPeople = new List<Person>(allPeople);
this.friends = new List<Person>();
}
public void BindData(/* control here */)
{
// Code would go here to set up the data binding between
// the friends list and the list box control
}
// Event subscriber for CheckedListBox.SelectedIndexChanged
public void OnGenderSelected(object sender, EventArgs e)
{
CheckedListBox listBox = (CheckedListBox)sender;
this.selectedGender = /* get selected gender from list box here */;
}
// Event subscriber for Button.Click
public void OnUpdateFriends(object sender, EventArgs e)
{
this.friends.AddRange(
from p in this.allPeople
where p.Gender == this.selectedGender
select p);
// If you use data binding, you would need to ensure a
// data update event is raised to inform the control
// that it needs to update its view.
}
}
// . . .
// On initialization, you'll need to set up the event handlers, etc.
updateFriendsButton.Click += controller.OnUpdateFriends;
genderCheckedListBox.SelectedIndexChanged += controller.OnGenderSelected;
controller.BindData(friendsListBox);
// . . .
Basically, I recommend not having controls talk directly, but rather through a controller-like class as above which has knowledge of the data model and the other controls in the view.
Of course it's possible: you need to make the link between the 2 controls in the form.
Just declare an event 'ButtonClicked' in control #1
Then make a public method 'PerformsClick' on the control #2
And in the form, in the constructor, after the call to InitializeComponent, link the event from the control #1 to the method to the control #2:
control1.ButtonClicked += delegate(sender, e) {
control2.PerformsClick();
};
(I type on the fly to give you an idea, it'll surely not compile)
If you want to pass any data, just add parameters in the PerformsClick method.