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.
Related
I'm currently working on a new GUI that has a listbox as a crucial element in it. So far I've managed to display and select multiple items in this listbox, which wasn't that big of a deal.
My goal is to have several .cs files(maybe in further expansion als vb script files) in a folder within the project, which are properly displayed in the main view listbox and will be executed if the corresponding item in the listbox is selected.
So far I've tried to build the listbox and all the other GUI stuff (buttons, text,...) and connected the listbox with a bindable collection of a script model(which is a own class for testing purposes at the moment and should be replaced with the correct .cs files)
In the code below you can see the work around with this custom class and the selection check for multiple listbox items.
private void Run_Click(object sender, RoutedEventArgs e)
{
//Show user the scripts which are being processed, these are the previous selected Scripts
List<string> selectedList = new List<string>();
foreach (ScriptModel selectedScript in MainListBox.SelectedItems)
{
selectedList.Add(selectedScript.Name.ToString());
}
//check if no Script was selected, and if so, just return/do nothing
if (selectedList.Count() == 0) { return; }
MessageBox.Show("The following Scripts will be processed: " + Environment.NewLine +
string.Join(Environment.NewLine, selectedList));
//Call the Connection for Data-Export
}
private BindableCollection<ScriptModel> _scriptscollection=new BindableCollection<ScriptModel>();
public BindableCollection<ScriptModel> ScriptsCollection
{
get { return _scriptscollection; }
set { _scriptscollection = value; }
}
I would like to know, how I can replace(or connect) these custom class with actual .cs files (which are some kind of scripts) in a project folder, so that I can display these file names and select the corresponding files for execution. (so the connection should work both ways)
I'm sorry if this question seems a bit weird and general, but I'm really confused about that.
I believe you have over complicated the matter. Here is the code that will find all of the .cs files in a directory and then upon selecting one in the ListBox will start that file.
It's hard to tell exactly what you're asking for but hopefully this helps.
XAML
<ListBox ItemsSource="{Binding ScriptFiles}" SelectedItem="{Binding SelectedScript}"/>
Code behind / ViewModel
public List<string> ScriptFiles => Directory.GetFiles(FilePath, "*.cs").ToList();
private string selectedScript;
public string SelectedScript
{
get { return selectedScript; }
set { selectedScript = value; Process.Start(value); }
}
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 am in need of some guidance for the following design.
I have a tab control that contains various group boxes. Within the group box, there are specific controls that relates to that group box. For example:
Now whenever a change is made to any control in the group box, the value for the control needs to be tracked because at the end of the application run cycle, the control data will need to be saved to a file that contains that value. An example file is:
HOT_STANDBY_FEATURE_ENABLE [val from control here]
HEART_BEAT_DIGITAL_OUTPUT [val from control here]
....
A design that I have in mind has another that has just properties that the group box form sets whenever a ValueChanged event occurs on a control.
Example code:
class ConfigurationValues
{
public int HotStandbyValue { get; set; }
public int HeartBeatDigitalOutputValue { get; set; }
//...add all other controls here
}
The downside that I see to this is that there are 40 controls on that tab page, so I'd have to manually type each property. When the file needs to be generated at the end of the application run cycle, I have a method that gets the value of the control need.
Example:
private void GenerateFile()
{
string[] file =
"HOT_STANDBY_FEATURE_ENABLE " + ConfigurationTabSettings.HotStandbyValue;
}
Another design consideration I need to make is that whenever a user clicks "Open Configuration File", the values from the file from disk need to be loaded into the properties so the form can take that data on startup and populate the controls within the group boxes with their respective values.
Any suggestions on this design would be greatly appreciated. I know this is not the most efficent way to do this and am not the most experienced programmer, so any Google keywords I can search for would be great also.
You could xml serialise and xml deserialise your ConfigurationValues class rather than writing manual "generate file" and "read file" methods
http://support.microsoft.com/kb/815813
You'll need to bind the controls Text or Value properties to the properties in your ConfigurationValues class e.g.
ConfigurationValues cv = Repository.ReadConfigValues();
numPulseFilterDelay.DataBindings.Add("Value", cv, "PulseFilterDelay");
// Add the rest of your control bindings here
on the btnSave_Click() of your Form, end the current edit on the form and save the config values
void btnSave_Click(object sender, EventArgs e)
{
BindingContext[cv].EndCurrentEdit(); // Commits all values to the underlying data source
Repository.SaveConfigValues(cv);
}
In your repository class you'll need methods to Load() and Save() the data. You can put XmlSerialization code in here, or write your own format (depending on your requirements)
public class Repository
{
public static ConfigurationValues LoadConfigValues()
{
var cv = new ConfigurationValues();
string[] lines = File.ReadAllLines("values.cfg");
foreach (string cfg in lines)
{
string[] nameValue = cfg.Split(new char[] { ' ' } ); // To get label/value
if (nameValue[0] == "HOT_STANDBY_FEATURE_ENABLE")
cv.HotStandbyFeatureEnable = nameValue[1];
else if (nameValue[0] == "SOME_OTHER_PROPERTY")
cv.SomeOtherProperty = nameValue[2];
// Continue for all properties
}
return cv;
}
public static void SaveConfigValues(ConfigurationValues cv)
{
var builder = new StringBuilder();
builder.AppendFormat("HOST_STANDBY_FEATURE_ENABLE {0}\r\n", cv.HostStandbyFeatureEnable);
// Add the rest of your properties
File.WriteAllText("values.cfg", builder.ToString());
}
}
So I have two comboBoxes (comboBoxFromAccount and comboBoxToAccount). Each has the same datasource, which is AccountsList (a list of BankAccount objects that was passed from the parent form).
I would like to make it so that if an item is selected in one of the comboBoxes, it would no longer be selectable in the other. The way I'm trying to do this is by copying the list of BankAccounts from the comboBoxFromAccount to the comboBoxTo account, and removing the selected index of comboBoxFromAccount from the comboBoxToAccount.
I think I'm close, but what seems to happen is I have a blank comboBoxToAccount.
Here is my code:
private BankAccountCollection accountsListTransferTo = new BankAccountCollection();
// public property for passing collection data to the dialog
public BankAccountCollection AccountsList
{
get { return accountsListTransferTo; }
set { accountsListTransferTo = value; }
}
// Initial loading
private void TransferFundsDialog_Load(object sender, EventArgs e)
{
textBoxAmount.Text = String.Empty;
textBoxAmount.Select();
comboBoxFromAccount.DataSource = AccountsList;
accountsListTransferTo.AddRange(AccountsList); // Copy content
accountsListTransferTo.Remove(comboBoxFromAccount.SelectedItem as BankAccount); // Remove item
comboBoxToAccount.DataSource = accountsListTransferTo; // Data binding
}
private void comboBoxFromAccount_SelectedIndexChanged(object sender, EventArgs e)
{
accountsListTransferTo.Clear(); // Clear list, if you don't to it, AddRange will just add more items.
accountsListTransferTo.AddRange(AccountsList); // Copy ALL accounts
accountsListTransferTo.Remove(comboBoxFromAccount.SelectedItem as BankAccount); // Remove selected, so user cannot transfer to same account
// Refresh data binding
comboBoxToAccount.DataSource = null;
comboBoxToAccount.DataSource = accountsListTransferTo;
// Select very first item in "TO" combobox
comboBoxToAccount.SelectedIndex = 0;
}
Help would be appreciated.
Try removing the line
comboBoxToAccount.DataSource = null;
I have a vague recollection about comboboxes having problems with this.
Another possible problem that I can see is that you are using accountsListTransferTo both as your master collection and the one where you are removing the selected account from. Every time comboBoxFromAccount_SelectedIndexChanged is called one more account will disappear from the collection (and therefore from the available options in comboBoxToAccount).
I think I have seen comboboxes behave in a way where the SelectedIndexChanged (or a similar) event is triggered as new items are being added. If that is the case here it will explain the empty comboBoxToAccount, because comboBoxFromAccount_SelectedIndexChanged will run once for each bank account being added, essentially removing them from the master list and then rebinding the reduced list. You can easily verify this with a break point in your event handler.
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.