I am writing a SharePoint app. There I have page with drop down list. I have
a handler for SelectedIndexChanged. I want to get the selected value but as CustomObject and the only option I see is string. I tried SelectedValue and it is still string.
That's how I set the list:
protected void Page_Load(object sender, EventArgs e)
{
List<CustomObject> customList = //retrieving data
myDropDownList.DataSource = customList.Select(x => new { x.Name, Value = x});
myDropDownList.DataTextField = "Name";
myDropDownList.DataValueField = "Value";
myDropDownList.DataBind();
}
And that's one of the ways I tried:
protected void myDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
var index = groupingDropDownList.SelectedIndex;
CustomObject obj = (CustomObject)myDropDownList.Items[index].Value;
obj.DoSomething();
}
Is it even possible? Or do I have to have somewhere Dictionary with with objects?
You will want to leverage the html5 data attributes that you can then place onto the dropdown options. Here is an example of what you could do with your data.
// add Agencies' addresses as HTML5 data-attributes.
var agencies = agencyNames.ToList();
for (int i = 0; i < requesting_agency.Items.Count - 1; i++) {
requesting_agency.Items[i + 1].Attributes.Add("data-address",
agencies[i].address);
servicing_agency.Items[i + 1].Attributes.Add("data-address",
agencies[i].address);
}
Then when processing the information you could do something like so.
var index = groupingDropDownList.SelectedIndex;
var selectedText = myDropDownList.Items[index].SelectedValue;
var selectedValue = myDropDownList.Items[index].Attributes["attribute"];
// put into obj
// do something with object
Let me know if you have any questions.
You 're binding a object (x => new { x.Name, Value = x}) to dropdown value, you should bind actual value to it.
Test demo:
public class CustomObject
{
public int ID { get; set; }
public string Name { get; set; }
public CustomObject(int _ID,string _Name)
{
this.ID = _ID;
this.Name = _Name;
}
}
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<CustomObject> customList = new List<CustomObject>();
customList.Add(new CustomObject(1,"test1"));
customList.Add(new CustomObject(2,"test2"));
myDropDownList.DataSource = customList.Select(x => new { x.Name, Value = x.ID });
myDropDownList.DataTextField = "Name";
myDropDownList.DataValueField = "Value";
myDropDownList.DataBind();
}
}
I need to call a web service that accepts a class structure as input. The class itself is made up of regular field types plus one or more instances of a subclass. I was given example code that populates the class, but with static data. I need to populate it with dynamic data from user input at runtime and am not certain of the correct method to populate the subclass (PaymentProposalDetail) with 1 or more sets of data.
Here is the static data provided as an example:
PaymentApproval pa = new PaymentApproval()
{
VendorId = "14771",
Company = "333-TTTT",
PaymentApprovalNumber = "12345678",
SubmissioNDate = DateTime.Today,
ValueDate = DateTime.Today.AddMonths(1),
TotalAmount = 200000.00,
PaymentInstructionId = "ABCDEFGH",
Currency = "USD"
Comment = ""
};
pa.Details = new PaymentProposalDetail[] {
new PaymentProposalDetail()
{
InvoiceNumber = "1234567",
PayAmount = 454880.46,
InvoiceCurrency = "USD"
},
new PaymentProposalDetail()
{
InvoiceNumber = "9876543",
PayAmount = 543340.67,
InvoiceCurrency = "USD"
}
};
The class definitions:
public partial class PaymentApproval : object, System.Runtime.Serialization.IExtensibleDataObject
{
private string BankIdField;
private string CommentField;
private string CompanyField;
private string CurrencyField;
private PaymentProposalDetail[] DetailsField;
private string PaymentApprovalNumberField;
private string PaymentInstructionIdField;
private System.DateTime SubmissioNDateField;
private decimal TotalAmountField;
private System.DateTime ValueDateField;
private string VendorIdField;
}
public partial class PaymentProposalDetail : object, System.Runtime.Serialization.IExtensibleDataObject
{
private string InvoiceCurrencyField;
private string InvoiceNumberField;
private decimal PayAmountField;
}
I guess I need to build an array of PaymentProposalDetail objects within my loop that is getting the data from the UI. So for each set of data I do
PaymentApproval pa;
/* populate regular fields in pa */
foreach (data UIdata in UIdataStruct)
{
PaymentProposalDetail pd = new PaymentProposalDetail();
pd.InvoiceNumber = UIdata.invoiceNumber;
pd.PayAmount = UIdata.payAmount;
pd.InvoiceCurrenct = UIdata.invoiceCurrency;
}
But then how do I add pd to pa.Details?
Add each PaymentProposalDetail item to a collection and assign it to the PaymentApproval.
PaymentApproval pa;
/* populate regular fields in pa */
List<PaymentProposalDetail> details = new List<PaymentProposalDetail>();
foreach (data UIdata in UIdataStruct)
{
PaymentProposalDetail pd = new PaymentProposalDetail();
pd.InvoiceNumber = UIdata.invoiceNumber;
pd.PayAmount = UIdata.payAmount;
pd.InvoiceCurrenct = UIdata.invoiceCurrency;
details.Add(pd);
}
pa.Details = details.ToArray();
So my program is going to end up being fairly large and I don't want a whole lot of code that could just be shortened. Here is one instance I am looking for some tips on:
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
string books = null;
// sets books to the clicked item
books = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
// Loads string to list box and image to selectedPictureBox when programming is selected
if (books == "Programming")
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile("programming.png");
bookListBox.Items.Add("Visual Basic");
bookListBox.Items.Add("Java");
bookListBox.Items.Add("C#");
}
// Loads string to list box and image to selectedPictureBox when Networking is selected
else if (books == "Networking")
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile("networking.png");
bookListBox.Items.Add("LAN Networks");
bookListBox.Items.Add("Windows Networking");
bookListBox.Items.Add("More About Networking");
}
// Loads string to list box and image to selectedPictureBox when Web is selected
else if (books == "Web")
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile("html.png");
bookListBox.Items.Add("Web Programming");
bookListBox.Items.Add("JavaScript");
bookListBox.Items.Add("ASP");
}
}
The code works fine but I was just hoping to get some tips on shortening this code if necessary, any input is appreciated.
Assuming you can use C# 7's new Tuples:
private Dictionary<string, (string image, List<string> books)> books = new Dictionary<string, (string image, List<string> books)>
{
{ "Programming", ("programming.png", new List<string> { "Visual Basic", "Java", "C#"} ) },
{ "Networking", ("networking.png", new List<string> {"LAN Networks", "Windows Networking", "More About Networking"}) },
{ "Web", ("html.png", new List<string> {"Web Programming", "Javascript", "ASP"}) }
};
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// sets books to the clicked item
string book = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
if (books.Keys.Contains(book))
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(books[book].image);
foreach(var b in books[book].books)
{
bookListBox.Items.Add(b);
}
}
}
But a class is likely even better:
public class BookGroup
{
public string ImagePath {get;set;}
public List<string> Books {get;}
public BookGroup(string imagePath, params string[] books)
{
ImagePath = imagePath;
Books = new List<string>(books.Length);
Books.AddRange(books);
}
}
Which isn't all that different to use right now, but it formalizes some things that might make this code easier to work with down the road, and it's possible if you can't use Tuples yet. I might also have a Book class by itself, just for fun, but for now:
private Dictionary<string, BookGroup> books = new Dictionary<string, BookGroup>
{
{ "Programming", new BookGroup("programming.png", "Visual Basic", "Java", "C#")},
{ "Networking", new BookGroup("networking.png","LAN Networks", "Windows Networking", "More About Networking") },
{ "Web", new BookGroup("html.png", "Web Programming", "Javascript", "ASP") }
};
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// sets books to the clicked item
string book = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
if (books.Keys.Contains(book))
{
bookListBox.Items.Clear();
BookGroup bg = books[book];
selectedPictureBox.Image = Image.FromFile(bg.ImagePath);
foreach(var b in bg.Books)
{
bookListBox.Items.Add(b);
}
}
}
Regardless, I'd definitely have a way to load these from a text file... likely a csv, or maybe even a small in-process database, so that I could update this listing without having to recompile or distribute new program code. And, with that in mind, in order to fit this data in a single structure in a single file, I'd likely also repeat the image and type with each book, so that my csv data looks like this:
Topic,Image,Title
Programming,programming.png,"Visual Basic"
Programming,programming.png,"Java"
Programming,programming.png,"C#"
Networking,networking.png,"LAN Networks"
Networking,networking.png,"Windows Networking"
Networking,networking.png,"More About Networking"
Web,html.png,"Web Programming"
Web,html.png,"Javascript"
Web,html.png,"ASP"
That changes the whole character of the code. I'm a bit biased, but I'd likely use this CSV Parser, and again assuming Tuples I'd produce something like this:
private List<(string Topic, string ImagePath, string Title)> books;
//In the form load code:
books = EasyCSV.FromFile("bookData.csv").Select(b => (b[0], b[1], b[2])).ToList();
//and finally, in the original selectindexchanged method:
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
string topic = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
var items = books.Where(b => b.Topic == topic).ToArray();
if(items.Length > 0)
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(items[0].ImagePath);
bookListBox.Items.AddRange(items);
}
}
Make objects and use databindings.
public class Book
{
public BookType BookType { get; set; }
public string Name { get; set; }
public string Image { get; set; }
}
public enum BookType
{
Programming,
Networking,
Web,
}
public partial class Form1 : Form
{
private readonly List<Book> _books = new List<Book>
{
new Book { Image = "programming.png", BookType = BookType.Programming, Name = "VB" },
new Book { Image = "programming.png", BookType = BookType.Programming, Name = "Java" },
new Book { Image = "programming.png", BookType = BookType.Programming, Name = "C#" },
new Book { Image = "networking.png", BookType = BookType.Networking, Name = "LAN Networks" },
new Book { Image = "networking.png", BookType = BookType.Networking, Name = "Windows Networking" },
new Book { Image = "networking.png", BookType = BookType.Networking, Name = "More About Networking" },
new Book { Image = "html.png", BookType = BookType.Web, Name = "Web Programming" },
new Book { Image = "html.png", BookType = BookType.Web, Name = "Javascript" },
new Book { Image = "html.png", BookType = BookType.Web, Name = "ASP" },
};
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var bookTypes = _books.GroupBy(b => b.BookType).Select(g => g.Key).ToList();
this.cboBookTypes.DataSource = bookTypes;
}
private void cboBookTypes_SelectedIndexChanged(object sender, EventArgs e)
{
var bookType = (BookType)this.cboBookTypes.SelectedItem;
var books = _books.Where(b => b.BookType == bookType).ToList();
var img = books.First().Image;
this.imgBook.Image = Image.FromFile(img);
this.lstBooks.DataSource = books;
this.lstBooks.DisplayMember = "Name";
}
}
If you are talking about the length of the code, I would suggest using switch-case-break-default construct
Switch the books variable.
This wont improve the performance though
I think you should create a class that represents book category. Then, you could simply iterate through all the category lists and extract the necessary information, like this:
string books = null;
books = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
for (int i = 0; i < categories.Count; i++) {
if (books == categories[i].Name) {
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(categories[i].ImagePath);
for (int j = 0; j < categories[i].Items.Count; j++) {
bookListBox.Items.Add(categories[i].Items[j]);
}
}
}
I would suggest to keep all the data in a configuration object and then iterate through that data when performing checks and assignments.
I would create a separate class to hold data for each book: name, picture file name and check box items string array.
Then I would create a list of that object and assign all the data manually on form initialization.
After that, in SelectedIndexChanged event handler, I would iterate (for loop) on each item and check if the book name matched. If it did, then I would use data from that object and then break; the loop.
I do not have visual studio, so giving you the points/suggestions to improve on.
switch should be preferred over if-elseif.
bookListBox.Items.Clear(); and selectedPictureBox.Image out of if block. Use a variable to set the image file name.
Create a class to represent a book list:
public class BookList
{
public string ImageName { get; set; }
public List<string> Items { get;set; }
}
Then create a dictionary to hold these items:
Dictionary<string, BookList> bookLists = new Dictionary<string, BookList>
{
{
"Programming",
new BookList { ImageName = "programming.png", Items = new List<string> { ... } }
}
...
};
Then modify your if statements to:
if (bookLists.ContainsKey(books))
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(bookLists[books].ImageName);
foreach (var b in bookLists[books].Items)
{
bookListBox.Items.Add(b);
}
}
I have defined variables as string arrays. I also have a form called form4 and on this form I have 1 textbox and 1 combobox.
I have this code in a class:
public class food
{
public string[] name1 = new string [20];
public string[] name2 = new string [50];
public string[] name3 = new string [40] ;
public string[] name = new string [20];
public string[] type = new string [15];
//private const int total = 11;
public int[] calories_ref;
public int i, i2;
public Form4 form = new Form4();
public food(string[] Name1, string[] Name, string[] Type1, int[] kcal)
{
name1 = Name1;
name = Name;
type = Type1;
calories_ref = kcal;
}
public food()
{
}
private void settypes()
{
type[0] = "Bebidas não alcoólicas";
type[1] = "Bebidas Alcóolicas";
type[2] = "Fruta";
type[3] = "Hidratos de Carbono";
type[4] = "Peixe";
type[5] = "Carne";
type[6] = "Cereais";
type[7] = "Lacticínios";
type[8] = "Óleos/Gorduras";
type[9] = "Leguminosas";
type[10] = "Legumes";
for (int i = 0; i < type.Length; i++)
{
form.comboBox1.Items.Add(type[i]);
}
}
In the settypes() method I define the various types of food, more concretly the food wheel. How can I can use these values as items in the combobox that is in form4?
You can add an array of strings using method AddRange(array[]) from comboBox.
form.comboBox1.Items.AddRange(type);
Here is a void you can use if you want to go beyond just one array.
public void AddToCombo(Array array, ComboBox c)
{
foreach(var a in array)
{
c.Items.Add(a);
}
}
You shouldn't be storing a Form4 object in your food class. Your code as it is creates a brand new Form4 every time the food object is created. As shown in the line:
public Form4 form = new Form4();
This won't actually be shown on screen though as you do nothing else with the form except add items to the ComboBox, which also wouldn't show on the screen.
Even if you were to get it shown on the screen, you will still get an error similar to:
Form4.comboBox1 is inaccessible due to its protection level
This is due to the fact that the ComboBox is created internally with private access modifier. (See http://msdn.microsoft.com/en-us/library/ms173121.aspx for more details).
What you need to do is get your existing Form4 to ask the food object to populate it's ComboBox by passing the ComboBox to a method on the food object similar to this example (in your Form4 code not your food code):
private void Form4_Load(object sender, EventArgs e)
{
food f = new food(); //or however you wanted to create the object
f.AddTypesToComboBox(this.comboBox1);
}
The AddTypesToComboBox method would be defined like this in your food object:
public void AddTypesToComboBox(ComboBox box)
{
for (int i = 0; i < type.Length; i++)
{
box.Items.Add(type[i]);
}
}
Also, at the moment the function won't actually add anything to the ComboBox as your type array is not being filled with data. You need to call settypes(); in the food object's constructors like this:
public food(string[] Name1, string[] Name, string[] Type1, int[] kcal)
{
settypes();
name1 = Name1;
name = Name;
type = Type1;
calories_ref = kcal;
}
public food()
{
settypes();
}
You will need to remove public Form4 form = new Form4(); from your variable declaration section as well as removing the following from your settypes() method:
for (int i = 0; i < type.Length; i++)
{
form.comboBox1.Items.Add(type[i]);
}
Your settypes() should only fill the data into the array, and not try and add it to the ComboBox.
If you want the items to be in the ComboBox just set the array as its datasource. You don't need to loop through the array and add the items one by one. It's a lot less code than the other solutions here.
public void SetTypes()
{
comboBox1.DataSource = new[]{
"Bebidas não alcoólicas",
"Bebidas Alcóolicas",
"Fruta",
"Hidratos de Carbono",
"Peixe",
"Carne",
"Cereais",
"Lacticínios",
"Óleos/Gorduras",
"Leguminosas",
"Legumes"
};
}
Not at my computer at the moment, but this should do it:
foreach(var type in type[])
{
form.comboBox1.Items.Add(type);
}
As simple as this:
public void yourMethodName() {
yourComboBoxName.removeAllItems();
for (YourObjectName object: yourArrayListName) {
yourComboBoxName.addItem(object.getWhatYouWanaGet());
}
}
Your remove the actual item from the list than you add the item you want to add :)
If this is an Array in Class1:
public static string[] session = new string[] { "2023-2024", "2022-2023","2021-2022" };
In C# (Windows Forms):
comboBox1.Items.Clear();
comboBox1.Items.AddRange(Class1.session);
I have a method called get Data which executes my SQL and returns some rows of ContactLists containing Aggregated Labels.At the moment this method is in my code behind and would like to move it to a separate Data Access class. I would appreciate your assistance. Thanks!
Is normal, if i understand your code, you do this operation after ContactList initialization:
contactList.Labels = new ObservableCollection<Label>()
{
new Label() {
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
For each ContactList is always added one item, you will do something like this:
contactList.Labels = new ObservableCollection<Label>();
foreach(var item in <yourLabelDataSource>)
contactList.Labels.Add(new Label(...));
The solution is like this:
Dictionary<int, ContactList> myContactDictionary = new Dictionary<int, ContactList>();
using (DB2DataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["CONTACT_LIST_ID"]);
if (!myContactDictionary.ContainsKey(id))
{
ContactList contactList = new ContactList();
contactList.ContactListID = id;
contactList.ContactListName = dr["CONTACT_LIST_NAME"].ToString();
contactList.Labels = new ObservableCollection<Label>()
{
new Label()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
myContactDictionary.Add(id, contactList);
}
else
{
//Add new label because CONTACT_LIST_ID Exists
ContactList contactList = myContactDictionary[id];
contactList.Labels.Add(
new Label()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
}
Ben, for your last question you can use this solution:
else
{
//Add new label because CONTACT_LIST_ID Exists
ContactList contactList = myContactDictionary[id];
string name = dr["LABEL_NAME"].ToString();
var label = contactList.Labels.Where(l => l.Name == name).FirstOrDefault();
if( label != null )
label.Count += Convert.ToInt32(dr["LABEL_COUNT"]);
else
{
contactList.Labels.Add(
new Label()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
I hope this code is readable and helpfulL!
}
This is other response:
Create and Object Model that can contain your required data:
public class DataResult
{
public ObservableCollection<AggregatedLabel> AggregatedLabels { get; set; }
public ObservableCollection<ContactList> ContactLists { get; set; }
}
You can build a method that return DataResult object, in your method (GetData()), you can valorize the two different properties (AggregatedLabels and ContactsList) with your DB Result. In the and you can return DataResult Object.
A little example here:
public DataResult GetData()
{
DataResult result = new DataResult();
result.AggregatedLabels = new ObservableCollection<AggregatedLabel>();
result.ContactLists = new ObservableCollection<ContactList>();
// Manipulate data result with your method logic like in this examle:
foreach(var something in dbResult)
{
ContactList cl = new ContactList() {
//Binding from something
}
result.ContactLists.Add(cl);
}
return result; //return your Object Model with required Data!
}
I hope it is conceptually clear