I'm using custom objects to bind to a GridView.
Suppose I have a collection of Car Companies (Audi, Ford, BMW, etc). Each Company object has properties like Id, Name, Country, etc.
Each Company also has a Collection of Cars. Each Car has properties like Id, Model, Year, etc.
I want to bind this info to a GridView.
So I'm retrieving a query of Companies and in first object of each Cars Collection, has data of one car (the object model is like this because in other scenarios I have to list all the cars of a Company).
There is no problem when I bind the Gridview to the Companies collection. I can list each company and each car info I want to show.
The problem arises when I want to set the DataKeyNames. I want to set it with the Id of each Car (not the Id of each company) for comparing cars.
I was trying something like this:
GridViewCompanies.DataSource = companies;
GridViewCompanies.DataKeyNames = new string[] { "Cars[0].Id" };
But it does not work, it says it does not contain a property with the name.
Is there any way to set it?
I don't want to bind the Gridview to a Cars collection instead because if I do it that way, I would miss the info of each Company and I need to use company's properties too.
Many thanks.
Try it:
var carCompanyList = new[]
{
new { Id = 1, Name = "Audi", Cars = new[] { new { Id = 10, Model = "Audi_Model_1" }, new { Id = 12, Model = "Audi_Model_2" } } },
new { Id = 2, Name = "Ford", Cars = new[] { new { Id = 20, Model = "Ford_Model_1" }, new { Id = 22, Model = "Ford_Model_2" } } }
};
var gridViewData = from carCompany in carCompanyList
select new
{
carCompany.Id,
carCompany.Name,
firstModelId = carCompany.Cars == null || carCompany.Cars.Count() == 0 ? 0 : carCompany.Cars.First().Id
};
CarModelGridView.DataSource = gridViewData;
CarModelGridView.DataKeyNames = new [] { "firstModelId" };
CarModelGridView.DataBind();
Related
it is my query:
from customer in db.tblCustomers
select new
{
ID = customer.CustomerID,
Mobile = customer.Mobile1,
LastName = customer.Family
};
for every customer there is tow mobile phones, I need to add a new entry if the second mobile phone is not null. also I should change the LastName for second entry to something like "Second Mobile". How can I get two different entry from one customer using linq query?
Using the same generated type you can't have one with only one property of phone number and another with two. You can do:
from customer in db.tblCustomers
select new
{
ID = customer.CustomerID,
Mobile = customer.Mobile1,
SecondMobile = customer.Mobile2, // will be null if no second mobile exists
LastName = customer.Family
};
Otherwise what you can do is create a custom type Customer that will have a single phone number and a derived type ExtendedCustomer with two - and just instantiate the one or the other. Something along the psudo:
from customer in db.tblCustomers
select customer.Mobile2 != null ? new Customer(...) : new ExtendedCustomer(...);
If what you mean is having two different objects in the resulted collection then use union:
List<Customer> result = new List<Customer>();
foreach(var item in db.tblCustomers)
{
result.Add(new Customer(/*data for first mobile phone*/);
if(item.Mobile2 != null)
{
result.Add(new Customer(/*data for second mobile phone*/);
}
}
Could you please try this if it helps?
var customers = db.tblCustomers.SelectMany(x => x.GetMultipleRow()).ToList();
GetMultipleRow is an extension method as below.
public static class CustomerExtensions
{
public static IEnumerable<Customer> GetMultipleRow(this Customer cust)
{
yield return new Customer { CustomerID = cust.CustomerID, Mobile1 = cust.Mobile1, Family = cust.Family };
/* Data for first mobile*/
if (cust.Mobile2 != null)
yield return new Customer { CustomerID = cust.CustomerID, Mobile1 = cust.Mobile2, Family = cust.Family };
/* Data for second mobile*/
}
}
My problem is that after creating an invoice, I can never get new line items to reference their corresponding sales order line item.
I have been generating invoices via SuiteTalk. When I initially create an invoice, I empty the lineItemList and add back in the items I need. I make sure the orderLine property matches the sales order line item line number. This works great.
But when I try and update the invoice with additional line items, I can never get the new items to retain their orderLine property. The orderLine property is used for the "Invoiced" column on the Sales Order.
In order to get the referencing to be correct, I need to delete the invoice and create it again with all of the line items I need.
Does anyone know if what I am trying to do is possible?
In this example, I use this CreateInvoice function to create the invoice from scratch and add it to NetSuite. Everything works as expected.
public void CreateInvoice(SalesOrder salesOrder) {
Invoice brandNewInvoice = new Invoice() {
createdFrom = new RecordRef() {
internalId = salesOrder.internalId,
},
entity = salesOrder.entity,
tranDate = endDate,
tranDateSpecified = true,
startDate = startDate,
startDateSpecified = true,
endDate = endDate,
endDateSpecified = true,
itemList = new InvoiceItemList(),
};
invoice.itemList.item = GetInvoiceItemList(salesOrder); //see the function shown further down
netSuiteService.add(brandNewInvoice);
}
In this example, the invoice is already created and so I get it from NetSuite and then replace the existing itemList with a new one. After the update, the invoice will now have NO orderLine property for any of the line items. The invoice also loses its "Created From" field because there are no line items with the orderLine property set.
public void UpdateInvoice(SalesOrder salesOrder, String invoiceInternalId) {
Invoice invoice = GetNetSuiteInvoice(invoiceInternalId);
invoice.itemList.item = GetInvoiceItemList(salesOrder); //see the function shown further down
netSuiteService.update(invoice);
}
this is the function used to create the itemList:
public InvoiceItem[] GetInvoiceItemList(SalesOrder salesOrder) {
InvoiceItem[] invoiceItemList = new InvoiceItem[salesOrder.itemList.item.Length];
for (int i = 0; i < salesOrder.itemList.item.Length; i++) {
SalesOrderItem soItem = salesOrder.itemList.item[i];
double quantity = 1;
invoiceItemList[i] = new InvoiceItem() {
item = new RecordRef() {
internalId = soItem.item.internalId,
name = soItem.item.name,
},
amount = quantity * Double.Parse(soItem.rate),
amountSpecified = true,
quantity = quantity,
quantitySpecified = true,
price = new RecordRef() {
internalId = soItem.price.internalId,
name = soItem.price.name,
},
rate = soItem.rate,
orderLine = soItem.line, //this will establish the link between the invoice and the sales order
orderLineSpecified = true,
taxRate1 = soItem.taxRate1,
taxRate1Specified = true,
};
}
return invoiceItemList;
}
Actually what you are looking for is the intialize operation. You need to use initialize in order for Netsuite to properly fill in the created from and orderline props. From the NS Help there is a C# example of creating a Cash Sale:
private void Initialize()
{
this.login(true);
InitializeRef ref1 = new InitializeRef();
ref1.type = InitializeRefType.salesOrder;
//internal id of the sales order to be converted to cash sale
ref1.internalId = "792";
ref1.typeSpecified = true;
InitializeRecord rec = new InitializeRecord();
rec.type = InitializeType.cashSale;
rec.reference = ref1;
ReadResponse read1 = _service.initialize(rec);
}
This is normal, when transforming a transaction to another transaction (e.g. SO to Inv, PO to IR). When you transform, most of the information from the source transaction will be carried over. Like what you are doing which is creating an Invoice from Sales Order(Base on your code below).
createdFrom = new RecordRef() {
internalId = salesOrder.internalId,
},
You don't need to get the line item information from the Sales Order and put it in the Invoice because it will be pre-populated once you create it form Sales Oder(unless you need to change a value of a line item column).
One behavior of a transformed record(Invoice in your case), if you remove a line item from the Invoice you will lose the link to the Sales order(orderLine) and if you remove all the line item you will totally lose the link between the two transactions (createdfrom). This is what you are experiencing. orderLine/createdFrom is a field populated by the system, it looks like you are populating it but you are not.
In my C# application I have a datagridview with 'person' data in it that means the datasource of this datagrisview is set with an IList of the class person.
My person model consists of the following fields (just the model, not the datagridview):
string foreName
string surname
int devisionId
int someOtherId
Organisation orga
Organisation is another model which is mapped as one-to-many with NHibernate. Among others organisation consists of the string:
string orgaName
Now comes the tricky part (for me)....
In my datagridview I dont want to have all fields of person, I just want to have the following:
foreName
surname
orga.orgaName
Getting the first twoe fields is easy:
dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname}).ToList();
This works fine so far but now I also want to have the name of the organisation within my datagridview so I tried this:
dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname, OrganisationName = x.Organisation.organName}).ToList();
This would also work fine if every person has an organisation, but thats not the fact. Some persons do not have an organisation so 'Organisation' is null and trying to grab Organisation.organName ends with a nullpointerexeption.
The question now is:
How can I write my select-statement for the datagridview-datasource so that the organisation name is shown when Organisation is not null, otherwisesomething else is printed to the datagridview (for example: no organisation available)
dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname, OrganisationName = x.Organisation == null ? "None" : x.Organisation.organName}).ToList();
Try this :
dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname, OrganisationName = x.Organisation != null ? x.Organisation.organName : "No organisation available"}).ToList();
I have a datagridvew with a bindinglist whose datasource is to an intersection table. I have an another bindinglist which acts as a lookup and is bound to one of the columns that is a DataGridViewComboBoxColumn type. I have simplified the binding lists as shown below:
public IList<Flight> flights = new List<Flight>()
{
new Flight { DepartureID = 1, DestinationID = 1, FlightNumber = "101" },
new Flight { DepartureID = 2, DestinationID = 2, FlightNumber = "202" },
new Flight { DepartureID = 3}
};
public IList<Departure> departures = new List<Departure>()
{
new Departure {ID = 1, City = "Toronto"},
new Departure {ID = 2, City = "Chicago"},
new Departure {ID = 3, City = "New York"}
};
public IList<Destination> destinations = new List<Destination>()
{
new Destination {ID = 1, City = "London"},
new Destination {ID = 2, City = "Paris"},
new Destination {ID = 3, City = "Amsterdam"}
};
I have five columns in my datagridview:
Depature ID: Textbox
Departure: Textbox
Destination ID: Textbox
Destination: Combobox
Flight Number: Textbox
I have three questions:
1) The departures are readonly. I would like to display the ID and the city. How can I add textbox to automatically look up the City value. I thought of the OnCellPainting event and looking it up but the e.Value is readonly. Is there some OnCellDrawing event similar to Delphi.
2) On the combobox for Destinations, once an user selects a value from the combobox, how do I also update the Destination ID also?
3) How do I handle the scenario where I only have values for Departure (e.g. this record (new Flight { DepartureID = 3}) throws an invalid value error because there's no value for the combobox to lookup)
1) The easiest way to set your Departure city would be using a ComboBox like the destination. Binding it to the list of Destinations and marking this column as ReadOnly. This would handle the Departure with no code.
2) You should bind your DataGridView and your List of flights with a BindingSource. Because your ComboBox ValueMember is your ID and your DisplayMember is the name of the city, it will automatically update your ID.
3) If you want to bind your data, the template should be the same. You should always have a destination and flight number in your list. If they don't have value, set them to null. You're gonna be able to handle the null value while you can't handle a non-existent attribute.
new Flight { DepartureID = 3, DestinationID = null, FlightNumber = null }
I am trying to concatenate two fields from a list to display in a dropdown.
Below is the code i am trying to use. I don't want to change the model of my products so I was trying to do something like that below but I can't figure anything out without building out my own object with the fields concatenated.
skuDropDown.DataSource = List<product>
skuDropDown.DataTextField = "ProductId" // want to combine with"Description";
skuDropDown.DataValueField = "ProductId";
skuDropDown.DataBind();
Thanks any ideas will help.
To assign the source with your given method, I would go for using LINQ to create an anonymous type with the properties you want. Something like
List<Product> products = new List<Product>();
products.Add(new Product() { ProductId = 1, Description = "Foo" });
products.Add(new Product() { ProductId = 2, Description = "Bar" });
var productQuery = products.Select(p => new { ProductId = p.ProductId, DisplayText = p.ProductId.ToString() + " " + p.Description });
skuDropDown.DataSource = productQuery;
skuDropDown.DataValueField = "ProductId";
skuDropDown.DataTextField = "DisplayText";
skuDropDown.DataBind();
IF you have a class to represent a product, just create a property that extend your class and return it combined, for example:
public string ID_Description {
get
{
return string.Format("{0} ({1})", Name, ProductId);
}
}
and, in your databind dropdown reference your property
skuDropDown.DataSource = productQuery;
skuDropDown.DataValueField = "ProductId";
skuDropDown.DataTextField = "ID_Description";
skuDropDown.DataBind();
You can do this:
List<Product>.ForEach(
x => skuDropDown.Items.Add(
new Item(x.ProductId + " " x.ProductDescription, x.ProductId)
);
Just loop through the list and add each item to the drop down list. It's what .net will do for you behind the scenes in your example.
Create a new class which extends the product, cast the List contents as the extended class, which contains a new property, which returns the concatenated values of ProductID and Description.
I think that should work OTOMH.
I know that you don't want to change the products structure, which is why I suggested making an extended class. But afaik it's not possible without binding it to a field of the object.
Unfortunately, if you're using databinding, the DataTextField must be the name of a field on your data source.
One thing you can do is iterate the items in the dropdownlist after you've bound them and modify their Text properties. The only other thing to do is get the concatenated field added to the data object.
All you need to do is override the .ToString() method of the Product.
public override string ToString()
{
return ProductID + " " + ProductDescription;
}
Then all you need to do is bind to the drop down. From my understanding, the dropdown lables ar bound to the tostring() of the objects in the collection it's bound to.
in other words, do this.
List<Product> products = new List<Product>();
products.Add(new Product() { ProductId = 1, Description = "Foo" });
products.Add(new Product() { ProductId = 2, Description = "Bar" });
var productQuery = products.Select(p => new { ProductId = p.ProductId, DisplayText = p.ProductId.ToString() + " " + p.Description });
skuDropDown.DataSource = productQuery;
skuDropDown.DataBind();