Hi I am using this function to show json in DataGridView but the problem is I have a list in the json file , this list doesn't display data in the grid
void show_data()
{
dataGrid.Columns.Clear();
dataGrid.DataSource = all_date;
}
my json file is as this
[{"Name":"350SC250-14","Fy":33.0,"GFy":false,"T":0.0713,"GT":false,"D":2.5,"Stud_D":1.5,"C":0.0,"B":3.5,"GB":false,"Manufacturer":"BIDDLE","CFS_File":"350SC250-14.cfss","Sub_SectionCount":0,"Sub_Section1":"","Sub_Section2":"","Sub_Section3":"","SectionType":3,"Configuration":0,"SectionParts":[{"Length":0.375,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":3.0,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":2.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":3.0,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.375,"Radius":0.0}]}]
my class is bellow
class dataForm
{
public string Name { get; set; }
public double Fy { get; set; }
public bool GFy { get; set; }
public double T { get; set; }
public bool GT { get; set; }
public double D { get; set; }
public double Stud_D { get; set; }
public double C { get; set; }
public double B { get; set; }
public bool GB { get; set; }
public string Manufacturer { get; set; }
public string CFS_File { get; set; }
public int Sub_SectionCount { get; set; }
public string Sub_Section1 { get; set; }
public string Sub_Section2 { get; set; }
public string Sub_Section3 { get; set; }
public int SectionType { get; set; }
public int Configuration { get; set; }
public List<SectionPart> SectionParts { get; set; }
}
class SectionPart
{
public double Length { get; set; }
public double Radius { get; set; }
}
so how can I diplay this sectionPart list ?
Add Newtonsoft.Json nuget :Install-Package Newtonsoft.Json to your project, and convert JSON to object using DeserializeObject
string data_from_json = #"[{'Name':'350SC250 - 14','Fy':33.0,'GFy':false,'T':0.0713,'GT':false,'D':2.5,'Stud_D':1.5,'C':0.0,'B':3.5,'GB':false,'Manufacturer':'BIDDLE','CFS_File':'350SC250 - 14.cfss','Sub_SectionCount':0,'Sub_Section1':'','Sub_Section2':'','Sub_Section3':'','SectionType':3,'Configuration':0,'SectionParts':[{'Length':0.375,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':3.0,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':2.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':3.0,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.375,'Radius':0.0}]}]";
dataGrid.Columns.Clear();
List<dataForm> all_date = JsonConvert.DeserializeObject<List<dataForm>>(data_from_json);
dataGrid.DataSource = all_date;
to display SectionParts only:
dataGrid.DataSource = all_date[0].SectionParts;
The problem you describe does not really have anything to do with JSON. The problem is with the Class dataForm. I do not like to say “problem” since the issue is fairly easy to understand, once you understand what your code is asking from the grid. The issue is that when the grid is given a DataSource like a List<T> or List<dataForm>, the grid will obligingly map each “primitive” property of the dataForm class (or any class T) to a column in the grid.
The grid is going to have to do something different when it comes across a property in the class that is a “Collection” or another “Class”. In this case, dataForm has a “collection” property …
public List<SectionPart> SectionParts { get; set; }
In this case the grid is not sophisticated enough to figure this out. It really is not going to know how to put “multiple” values into a single cell. Therefore, the grid will ignore collections as you obviously already know. This same Idea applies if the property in the class is another class… it will not display it.
Bear in mind, as other have commented, there are third-party controls that may have features that will show the collections or classes. Unfortunately, the out of the box DataGridView is fairly limited. In most cases, the easiest way to deal with this is in a “Master/Detail” type display, where the first grid displays the class and the second grid displays the collection of the “selected” item in the first grid.
With that said, there are ways to achieve your goal without a lot of work depending on “how” you want to “display” the data to the user. IMHO a master-detail is usually the easiest to implement and is user friendly. Another option, is to “flatten” each of the items in the collection creating a column(s) for each item in the collection. This is much more work and you will possibly end up with many columns and many empty cells… not user friendly. The last option which may work for your case is to create a public property in the dataForm class that “exposes” the SectionParts collection as a single string.
Example: in this case, the SectionPart class has two (2) properties.
public double Length { get; set; }
public double Radius { get; set; }
To help later, let’s override the ToString method to return the two values as a single string. Something like…
public override string ToString() {
return "L: " + Length + " R: " + Radius;
}
Moving to the dataForm class there is a “collection” of the SectionPart objects. To display ALL the section parts into a single cell we need to create a single string from ALL the section parts. Each part will be on a single line using the SectionParts ToString method we added above. To make this “single” string display in the grid, we need to add a new property to the dataForm class that returns this “list of parts” as a single string. This property may look like…
public string SectionPartsList {
get {
StringBuilder sb = new StringBuilder();
foreach (SectionPart sp in SectionParts) {
sb.AppendLine(sp.ToString());
}
return sb.ToString();
}
}.
You may need to adjust the grids rows height to accommodate, however, in my test, if you simply hover your cursor over the cell the list will display.
Lastly, for completeness, let us assume, that instead of a “List” of SectionParts the class had a single instance of this class.
public SectionPart SingleSectionPart { get; set; }
Again the grid is going to ignore this “class” property when creating the columns in the grid. However, if you wanted those two fields displayed in the grid, then it would be fairly simple to create two properties in the dataForm class that simply return those values. In this case, the two properties may look like…
public double SP_L {
get {
return SingleSectionPart.Length;
}
}
public double SP_R {
get {
return SingleSectionPart.Radius;
}
}
I hope this makes sense and helps.
i'm working on this since a while but didn't solved my problem.
The Case:
I have list A which contains objects of Info.
Info has the properties id, name and list B which contains objects of Details.
Details has the properties id, Name and a bool.
Is it possible to bind list A to a ListView and show the property of an object from list B where the bool is true?
edit:
List B contains more than one object but only one of the objects has a true bool, the others have false. I want to show the Name of the object with the true bool in the GridViewColumn with Binding but didn't find a way till now
public class Info
{
public int Id { get; set; }
public string Name { get; set; }
List<Detail> Details { get; set; }
public string GoodDetails
{
get { return String.Join(",", Details.Where(x => x.Good == true).Select(y => y.Name)); }
}
}
public class Detail
{
public int Id { get; set; }
public string Name { get; set; }
public bool Good { get; set; }
}
So taking from your list of Details with the bool (which I called Good) set to true, I make a separate property called GoodDetails which pulls all of the names into a comma delimited string. So you just bind to GoodDetails
My application's front end is a DataGrid whose contents are passed to an Excel-generating method.
The catch is that the DataGrid deals with 13 columns: 10 of them are fixed (i.e., passed to Excel) while each of the last 3 is optional.
public class GridModel
{
public string Item { get; set; }
public string ItemName { get; set; }
public double TotalHeight { get; set; }
public double AGLheight { get; set; }
public double Embedment { get; set; }
public string Shape { get; set; }
public double TipDiameter { get; set; }
public double BaseDiameter { get; set; }
public double Taper { get; set; }
public double ShearReaction { get; set; }
// The following are optional, in 8 combinations, from all present to all absent
public double Camber { get; set; }
public double Rake { get; set; }
public double Angle { get; set; }
}
Being a C# newbie, I am considering the different approaches.
How would you folks deal with this? The simplest idea that comes to mind is to add 3 flags to the model:
bool IsColumn1Present;
bool IsColumn2Present;
bool IsColumn3Present;
Another way would be to add a level to the hierarchy, so each of the 'special' columns contains its own embedded flag:
if (Camber.flag) add(Camber.value);
That said, I would like to have the ability to somehow remove those 3 properties, so any attempt to access them would result in an error or impossibility.
If such thing exists, I guess it would be called "Variant Properties".
TIA
Note: I have solved this already by the manipulation of the Visibility.Visible field at the GUI level. Gurus, however, tell us that this is a bad idea. Best practices dictate that this facility should be part of the Model.
You could use nullable properties:
public double? Camber { get; set; }
Then check them for a value in your business logic:
if (thing.Camber.HasValue)
{
DoSomething(thing.Camber.Value);
}
It sounds like this might be exactly what you're after, given your comment on "variant" properties.
More info: http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx
Update: If you need to switch them off application-wide (as per your comment), you could either avoid setting the value in the first place when it's not wanted (this would be preferable as this is, as far as I'm concerned, business logic and doesn't belong in your dumb model classes) or extend this with a custom accessor:
private double? _camber;
public double? Camber
{
get
{
return ModelSettings.CamberEnabled
? _camber
: null;
}
set;
}
Then have some static/constant property somewhere:
public static class ModelSettings
{
public const bool CamberEnabled = true;
}
If the number of columns is constant (meaning the user can't add 'custom' columns), I would suggest a bit-field enum value like so:
[Flags]
public enum ColumnFlags
{
None = 0,
Camber = 0x1,
Rake = 0x2,
Angle = 0x4,
// Other optional columns here, keep them powers of 2!
}
Then in your Model class, keep a value such as:
public ColumnFlags ColumnFlags { get; set; }
Then you can use...
if(model.ColumnFlags.HasFlag(ColumnFlags.Camber))
{
// Do something here...
}
if(model.ColumnFlags.HasFlag(ColumnFlags.Rake))
{
// Do something here...
}
EDIT: Alternatively, you can use the Nullable<T> types to specify a "missing" or "empty" value.
I have two classes which contain the same fields, however one inherits some properties from somewhere else and the other does not.
I have created a generic list using the class "ZEUS_ResearchStocksHistory" , but then I need to clone all of the fields over to the other list "ZEUS_ResearchStocksHistoryWithExcel". I don't want to have to loop through each field in one list and populate the other, or write some sort of linq join, there must be a faster way?
The reason I can't use the same class in both instances is that when inheriting the ExcelReport function it adds additional fields which I do not want when I display this list in a data grid.
internal class ZEUS_ResearchStocksHistory
{
public String Amendment { get; set; }
public String AmendedBy { get; set; }
public String Sedol { get; set; }
public String Date { get; set; }
}
internal class ZEUS_ResearchStocksHistoryWithExcel : ExcelReport
{
public String Amendment { get; set; }
public String AmendedBy { get; set; }
public String Sedol { get; set; }
public String Date { get; set; }
}
Is this possible?
Thanks
Did you have a look at automapper?
example from codeproject:
CustomerViewItem customerViewItem =
Mapper.Map<Customer, CustomerViewItem>(customer);
Check out Automapper, which is designed to do exactly this. Automapper is up on NuGet.
http://lostechies.com/jimmybogard/2009/01/23/automapper-the-object-object-mapper/
You could do something as simple as:
Mapper.CreateMap<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>();
var newObject = Mapper.Map<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>(oldObject);
Or, since you said you have a list, you could do:
var newList = oldList.Select(x => Mapper.Map<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>(x));
There seems to be many questions relating to binding on a DataTable, but none that I could find touch on my exact situation.
I'm currently ajax binding on a list of objects like such:
public class MyObject
{
public string Name { get; set; }
public string Something1{ get; set; }
public string Something2{ get; set; }
public string Something3 { get; set; }
public MyObjectMyObject2 { get; set; }
}
public class MyObject2
{
public string Color { get; set; }
public string Something4 { get; set; }
}
[GridAction]
public ActionResult GetData()
{
var data = QueryDatabaseAndInstantiateAListOfMyObjects();
return View(new GridModel(data));
}
And with a view like such:
<%= Html.Telerik().Grid<MyObject>()
.DataBinding(dataBinding => dataBinding.Ajax().Select("GetData", new { action = "GetData" }))
.Name("Grid1")
.Columns(columns =>
{
columns.Bound(o => o.Name).Title("Name1");
columns.Bound(o => o.MyObject2.Color).Title("Color");
columns.Bound(o => o.Something1).Hidden(true);
columns.Bound(o => o.Something2).Hidden(true);
columns.Bound(o => o.Something3).Hidden(true);
columns.Bound(o => o.MyObject.Something4).Hidden(true);
})
%>
This works great and all as I'm able to sort, group, and all the above.
My situation is I have many properties on MyObject and some edges cases are popping up that are yielding a couple megabytes of response data. The reason being there are many many hidden columns that are situational dependent that a user can right-click to show. The problem is, data for all these extra hidden columns are included in the response data even when they're not used per say. And since the act of grouping, un-grouping, showing and hiding columns fetches for data anyways, why does all the extra data have to come with it?
If I could have only the data returned that is necessary to populate the visible columns plus say a couple that I could mark somehow with a custom attribute, that would immensely help cut back on the size of the returned data.
So I took to converting my list of objects to a DataTable that I could then conditionally add columns + data for and then feed that to the GridModel. This worked well up until trying to group by a column that is in a nested object such as o.MyObject2.Color.
I run into this exception:
Property with specified name: MyObject2.Color cannot be found on type: System.Data.DataRowView
I guess this makes sense, but how do I overcome this? When I use Object Shredder, it sets each property of MyObject loosely typed such as ["Name"] as a string and ["MyObject2"] as a MyObject2. But everything past ["MyObject2"] is strongly typed: (dataRow["MyObject2"] as MyObject2).Color. And this is where is gets over my head.
Is there another way to overcome my initial issue of all that extra data being sent that isn't used? Or, is there any advice with the DataTable bit? I've also tried converting the DataTable to a IEnumerable with no such luck. The serialized Json is quite empty. I've also tried flattening all nested objects such as having datarow["MyObject2.Color"] as string, but this wreaks havok when referencing this column in JavaScript so I had to go with an underscore delimiter ["MyObject2_Color"] but this really screws up binding Columns in the UI. There has to be a way!
I don't see any reason to bring back your full object just to show Color and Something4. Try flattening it out. Something like this where you just assign the values of Color and Something4 to the properties of the model.
public class MyObject
{
public string Name { get; set; }
public string Something1{ get; set; }
public string Something2{ get; set; }
public string Something3 { get; set; }
public string Something4 { get; set; }
public string Color { get; set; }
}
[GridAction]
public ActionResult GetData()
{
var data = QueryDatabaseAndInstantiateAListOfMyObjects();
data.Something4 = MyObject2.Something4;
data.Color = MyObject2.Color;
return View(new GridModel(data));
}
This is the true Answer, but I'm giving credit to Alfalfa for the idea.
I continue along with the DataTable idea, but use getters to expose each nested object property. It's a bit conveluded and brittle, but it works!
public class MyObject
{
public string Name { get; set; }
public string Something1{ get; set; }
public string Something2{ get; set; }
public string Something3 { get; set; }
[ScriptIgnore()]
public MyObjectMyObject2 { get; set; }
public string Color { get { return this.MyObject2.Color; } }
public string Something4 { get { return this.MyObject2.Something4; } }
}
public class MyObject2
{
public string Color { get; set; }
public string Something4 { get; set; }
}