I'm working on building a List using Combobox that when a Client is selected from the combo list, it loads a specific URL. Problem is the List is blank.
Below is the code, but I don't see what I'm missing but it could be simple oversight since this is the first time I'm building a Combobox like this.
public partial class Form1 : Form
{
List<MyClient> clients;
public Form1()
{
InitializeComponent();
clients = new List<MyClient>();
clients.Add(new MyClient { ClientName = "Client 1", UrlAddress = #"http://www.google.com" });
BindBigClientsList();
}
private void BindBigClientsList()
{
BigClientsList.DataSource = clients;
BigClientsList.DisplayMember = "ClientName";
BigClientsList.ValueMember = "UrlAddress";
}
private void BigClientsList_SelectedIndexChanged(object sender, EventArgs e)
{
MyClient c = BigClientsList.SelectedItem as MyClient;
if (c != null)
{
string url = c.ClientName;
Process.Start(url);
}
}
}
class MyClient
{
public string ClientName { get; set; }
public string UrlAddress { get; set; }
}
You're missing the last line: DataBind
private void BindBigClientsList()
{
BigClientsList.DataSource = ClientSize;
BigClientsList.DisplayMember = "ClientName";
BigClientsList.ValueMember = "UrlAddress";
BigClientsList.DataBind;
}
Your constructor should look like this
public Form1()
{
InitializeComponent();
List<MyClient> clients = new List<MyClient>();
clients.Add(new MyClient { ClientName = "Client 1", UrlAddress = #"http://www.google.com" });
foreach(MyClient client in clients)
{
BigClients.Items.Add(client);
}
}
This adds two things:
Add the object to the ComboBox. Without that, how is the item supposed to appear in the ComboBox?
Put the code after the InitializeComponent() statement. Otherwise, when you try to add the MyClient object to the ComboBox, it will throw a NullReferenceException.
Related
I am new to C#, and am trying to create a basic project in which the user enters Client details (name, phone, email) and selects their location by a radio button as one out of three locations.
The locations are radio buttons within the menu item, 'MenuLocClient'.
Then the user clicks 'Add Client' to see the Client's name to appear in the list box,'LstClients'.
When the client name is selected from the list box, and the user clicks 'Show Client' the window, Client details is brought up with the client information (name, phone, email, location) like so:
I have my client class defined as:
namespace WpfApp_project
{
public partial class Client
{
public string Name { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Location { get; }
public Client(string n, string p, string e, string l)
{
Name = n;
Phone = p;
Email = e;
Location = l;
}
}
}
In my ClientDetails window:
public partial class ClientDetails : Window
{
public ClientDetails(Client c)
{
InitializeComponent();
LblNameClient.Content = c.Name;
lblPhoneClient.Content = c.Phone;
lblEmailClient.Content = c.Email;
blLocClient.Content = c.Location;
}
}
In my main Window:
public partial class MainWindow : Window
{
// My client list
List<Client> ClientList = new List<Client>();
public MainWindow()
{
InitializeComponent();
}
// method to select location via radio button. it would be something like this?
public void radio_selected(…)
{
string selected;
if (RBLocE.isChecked) { selected = “Edinburgh”};
else if (RBLocG.isChecked) { selected = “Glasgow”};
else if (RBLocO.isChecked) { selected = “Other”};
Client c = …
c.Location = selected;
}
// method to create a new client on click
private void newClient(object sender, RoutedEventArgs e)
{
Client c = new Client(boxClientName.Text, boxClientPhone.Text, boxClientEmail.Text, ...); # add selected for location?
BoxClientName.Clear();
boxClientPhone.Clear();
boxClientEmail.Clear();
#rb.Checked = false;?
ClientList.Add(c);
lstClients.ItemsSource = null;
lstClients.ItemsSource = ClientList;
}
// method to show details of selected client
private void showDetails(object sender, RoutedEventArgs e)
{
Client c = lstClients.SelectedItem as Client;
if (c != null)
{
ClientDetails w = new ClientDetails(c);
w.Show();
}
}
Can someone please help me how to define my methods in MainWindow to add Location as selected by a radio button?
There are many ways to do this. Normally I would bind to an enum with a value converter as shown in this answer.
However as you are not using binding at all I'm going to assume you are at an earlier stage of learning and this can be done with a simple if/else in code behind. In fact you mostly already did this in your radio_selected method, you just need to modify it slightly to return the value.
public string GetSelectedLocation()
{
string selected = string.Empty;
if (RBLocE.isChecked) { selected = “Edinburgh”};
else if (RBLocG.isChecked) { selected = “Glasgow”};
else if (RBLocO.isChecked) { selected = “Other”};
return selected;
}
Then when creating your new client:
Client c = new Client(boxClientName.Text, boxClientPhone.Text,
boxClientEmail.Text, GetSelectedLocation());
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;
}
let me describe the situation. Winforms C#
I have xml file with data. I load this data to an user defined class object using Deserialize.
Based on this object with data, I build [in Form] UI: many tabPages of custom controls (textBox, 2 buttons in groupBox). I can also save this user defined class object using Serialize to XML file.
Question:
When I update textBox.Text in Form UI in custom control I do not know how to keep connection with the object with data (Layout layout) and save the updated object with data to XML. The change of text happens only in user custom control TextBox. I want to update data from UI in data object (layout) and then simply save with Serialization.
user class:
public class Layout
{
public string type;
public List<TabPage> TabPageList;
public Layout()
{
this.TabPageList = new List<TabPage>();
}
}
public class TabPage
{
public string text;
public List<ActionGroup> ActionGroupList;
public TabPage()
{
this.ActionGroupList = new List<ActionGroup>();
}
}
public class ActionGroup
{
public string type;
public string text;
public string sourceLocal;
public string sourceRemote;
public ActionGroup()
{
this.type = string.Empty;
this.text = string.Empty;
this.sourceLocal = string.Empty;
this.sourceRemote = string.Empty;
}
}
Custom control:
public partial class ViewActionGroup : UserControl
{
public string type;
public string text;
public string sourceLocal;
public string sourceRemote;
public bool isRemote;
public bool isDone;
public ViewActionGroup()
{
this.type = string.Empty;
this.text = string.Empty;
this.sourceLocal = string.Empty;
this.sourceRemote = string.Empty;
this.isRemote = false;
this.isDone = false;
InitializeComponent();
}
public ViewActionGroup(ActionGroup actionGroup)
{
this.type = actionGroup.type;
this.text = actionGroup.text;
this.sourceLocal = actionGroup.sourceLocal;
this.sourceRemote = actionGroup.sourceRemote;
this.isRemote = false;
this.isDone = false;
InitializeComponent();
groupBox1.Text = text;
button1.Text = type;
button1.Click += new EventHandler(Button_Click);
textBox1.Text = sourceLocal;
textBox1.TextChanged += new EventHandler(textBox1_TextChanged);
}
public void ChangeToRemote()
{
isRemote = true;
textBox1.Text = this.sourceRemote;
}
public void ChangeToLocal()
{
isRemote = false;
textBox1.Text = this.sourceLocal;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (this.isRemote)
{
this.sourceRemote = textBox1.Text;
}
else
{
this.sourceLocal = textBox1.Text;
}
}
Creating UI where I loose connection between UI and data object:
private void CreateLayout(Layout layout)
{
this.Text = layout.type;
TabControl tabControl = new TabControl();
tabControl.Dock = DockStyle.Fill;
int tabCount = 0;
foreach (TabPage tabpage in layout.TabPageList)
{
int actionCount = 0;
tabControl.TabPages.Add(tabpage.text);
foreach (ActionGroup actionGroup in tabpage.ActionGroupList)
{
ViewActionGroup view = new ViewActionGroup(actionGroup);
view.Location = new Point(0, actionCount * view.Height);
tabControl.TabPages[tabCount].Controls.Add(view);
tabControl.TabPages[tabCount].AutoScroll = true;
tabControl.TabPages[tabCount].AutoScrollMinSize = new System.Drawing.Size(tabControl.Width/2,tabControl.Height);
actionCount++;
}
tabCount++;
this.panelMain.Controls.Add(tabControl);
}
}
There are two common ways:
One is a routine WriteDataIntoControls and another ReadDataFromControls where you transfer the data to and from your visible controls manually (advantage: highest degree of control). In this case you'd have to read your object from your XML source, deserialize it into your business object and create all visible controls together with their value. On saving you'd have to transfer all values into your business object and serizalize it after this.
The second is DataBinding (advantage: highest degree of automation). Read here: https://msdn.microsoft.com/en-us/library/ef2xyb33%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
You can bind to simple values as well as to lists (including navigation) or complex objects.
You find a tutorial here: http://www.codeproject.com/Articles/24656/A-Detailed-Data-Binding-Tutorial
#Shnugo Thank You for your feedback. The tutorial you posted did not help because it is too hard for me but Data Binding topic gave me some clue.
Here easy tutorial in VB actually but simple. It helped me to do it quickly in C#.
https://www.youtube.com/watch?v=jqLQ2K9YY2A
C# solution
class MyObject
{
string name;
public MyObject()
{ }
public string Name
{
get { return name;}
set { name = value; }
}
}
public partial class Form1 : Form
{
MyObject obj = new MyObject();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
obj.Name = "Lucas";
textBox1.DataBindings.Add("Text", obj, "Name", true, DataSourceUpdateMode.OnPropertyChanged);
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = obj.Name;
}
}
Im having some trouble updating a listbox when new data is added to it. This is my code
The my listbox has
<ListBox Name="EmailList" ItemsSource="{Binding ListBoxData, Mode=TwoWay}"
And here is my program:
public partial class MainWindow : Window
{
string hostname = Properties.Settings.Default.pop_host;
int port = Properties.Settings.Default.pop_port;
bool useSsl = Properties.Settings.Default.pop_usessl;
string username = "recent:" + Properties.Settings.Default.username;
string password = Properties.Settings.Default.password;
// When this button is pressed the program starts a backgroundworker
// that begins the download of mails
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker getNewMail = new BackgroundWorker();
getNewMail.DoWork += newEmail;
getNewMail.RunWorkerAsync();
getNewMail.RunWorkerCompleted += updateList;
}
// The actual function that downloads the mails (Using OpenPOP)
private void newEmail(object sender, DoWorkEventArgs e)
{
List<Message> allEmail = FetchAllMessages(hostname, port, useSsl, username, password);
ListBoxData = new List<EmailEntry> { };
foreach (Message singleEmail in allEmail)
{
var mailData = new ListBoxDataClass { theMessage = singleEmail, truncate = 40 };
readyUpListBoxData(mailData);
ListBoxData.Add(new EmailEntry { from = mailData.displayName, subject = mailData.partOfBody, messageID = singleEmail.Headers.MessageId.ToString() });
}
}
public class ListBoxDataClass
{
public Message theMessage { get; set; }
public int truncate { get; set; }
public string partOfBody { get; set; }
public string displayName { get; set; }
}
// A function that does different things with the downloaded data
public void readyUpListBoxData(ListBoxDataClass data)
{
MessagePart theEmailTxt = data.theMessage.FindFirstPlainTextVersion();
string noLineBreaks = theEmailTxt.GetBodyAsText().ToString().Replace(System.Environment.NewLine, " ");
data.partOfBody = noLineBreaks.Length <= data.truncate ? noLineBreaks : noLineBreaks.Substring(0, data.truncate) + " ..";
data.displayName = data.theMessage.Headers.From.DisplayName.ToString();
if (data.displayName == "")
{
data.displayName = data.theMessage.Headers.From.Address.ToString();
}
data.displayName += " <" + data.theMessage.Headers.From.Address.ToString() + ">";
}
}
I believe im supposed to use something called observable collection or something like that? I just cannot see how i can use that here in my program. I hope that some of you guys can assist me in the usage of Observable collection or point me to something else i can use, that does what i need.
I was thinking about using something like timer to achieve it, but im not sure that it would be good practice ?
Create public property for your ListBoxData as follows:
public partial class MainWindow : Window
{
public ObservableCollection<EmailEntry > ListBoxData{get;set;}
public MainWindow()
{
ListBoxData = new ObservableCollection<EmailEntry >();
InitializeComponents();
}
private void newEmail(object sender, DoWorkEventArgs e)
{
List<Message> allEmail = FetchAllMessages(hostname, port, useSsl, username, password);
foreach (Message singleEmail in allEmail)
{
var mailData = new ListBoxDataClass { theMessage = singleEmail, truncate = 40 };
readyUpListBoxData(mailData);
ListBoxData.Add(new EmailEntry { from = mailData.displayName, subject = mailData.partOfBody, messageID = singleEmail.Headers.MessageId.ToString() });
}
}
You can either implement INotifyPropertyChanged and then raise ListBoxData property when you're done adding or just change your ListBoxData to ObservableCollection because it implements INPC by default.
Hi coders I have yet another question involving data binding in winforms. I set up a test applications where I have a bindinglist composed of structs called CustomerInfo. I have bound a listbox control to this list and spun a thread to add CustomerInfo items to the bindinglist.
namespace dataBindingSample {
public partial class Form1 : Form {
public BindingList<CustomerInfo> stringList = new BindingList<CustomerInfo>();
public Thread testThread;
public Form1() {
InitializeComponent();
stringList.AllowNew = true;
stringList.RaiseListChangedEvents = true;
listBox1.DataSource = stringList;
testThread = new Thread(new ThreadStart(hh_net_retask_request_func));
testThread.Priority = ThreadPriority.Normal;
}
private void hh_net_retask_request_func() {
int counter = 1;
while (true) {
CustomerInfo cust = new CustomerInfo();
cust.Name = "Customer "+ counter.ToString();
this.Invoke((MethodInvoker)delegate {
stringList.Add(cust);
});
counter++;
Thread.Sleep(1000);
}
}
private void Form1_Load(object sender, EventArgs e) {
testThread.Start();
}
}
public struct CustomerInfo {
public string Name {
set {
name = value;
}
get {
return name;
}
}
private string name;
}
}
What I see in the list box is the name of the struct dataBindingSample.CustomerInfo as opposed to the property of the struct. I was under the impression that non complex binding took the first available property.
Please educate me as to what I am doing wrong.
Thanks,
You'll need to either add an override of ToString() to your CustomerInfo class that returns what you'd like displyed in your list box, or set listBox1.DisplayMemer = "Name" before setting the DataSource.