PDA

View Full Version : [CLOSED] Grouping in property grid



ingbabic
Oct 15, 2015, 10:53 AM
I need a feature of categorizing (grouping, see the picture) properties in property grid. I saw possibility which was suggested in this thread (http://forums.ext.net/showthread.php?12454-CLOSED-PropertyGrid-with-property-separator), but it doesn't seem to work. I guess it is because it was a sample for Ext.NET 1.x. Maybe in 2.5.x there is some other way?

24278

Daniil
Oct 15, 2015, 3:52 PM
Hi @ingbabic,


Maybe in 2.5.x there is some other way?

Maybe, there is an other way, but I doubt it would be a better way.

I tend to think a GetRowClass approach is going to work for v2 as well, but CSS probably needs adjusting.

ingbabic
Oct 16, 2015, 7:32 AM
...but CSS probably needs adjusting


Could you please help me in that?

Daniil
Oct 16, 2015, 7:59 AM
Yes. I would recommend to start inspecting HTML elements (group rows) and looking for the "my-class" CSS class.

Pretty much the same process as demonstrated in this video:
CSS Change TabPanel Header Color - Ext.NET on Vimeo (http://vimeo.com/10076549)

ingbabic
Oct 19, 2015, 3:34 PM
I'm not sure if I did it right but class for separator row is: x-grid-row my-class x-grid-data-row,

while for other "normal rows" class is x-grid-row x-grid-data-row and x-grid-row x-grid-row-alt x-grid-data-row alternatively.

Separator row looks like other rows however (even the class is not the same as for other rows)

Daniil
Oct 19, 2015, 4:47 PM
Please provide a full test case with your adjustments of CSS rules. Meanwhile, while expecting HTML elements, do you see those rules are being applied?

ingbabic
Oct 20, 2015, 11:05 AM
No, rules are not applied. Here is complete sample. There you will see three problems. Before select change occurs separator isn't painted well. After select change next problem is (unwanted) appearance of id in property grid and (unwanted) disappearing of separator. For this second problem I thought that solution might be not to just simply setSource with selected.data[0], but to recreate it.



<style>
.x-props-grid .x-grid3-body .x-grid3-row.my-class td {
background-color: Red !important;
border-right-color: Red;
}

.x-props-grid .x-grid3-row.my-class .x-grid3-td-name .x-grid3-cell-inner {
background-image: none !important;
}

</style>

@Html.X().ResourceManager()

@(
Html.X().Panel().Layout(LayoutType.HBox).LayoutCon fig(new HBoxLayoutConfig { Align = HBoxAlign.Stretch })
.Items
(
Html.X().GridPanel().Title("GridPanel with PropertyGrid").Flex(8)
.Store
(
Html.X().Store().AutoLoad(true).Proxy(Html.X().Aja xProxy().Url(Url.Action("GetObjects")).Reader(Html.X().ArrayReader().Root("data")))
.Model
(
Html.X().Model()
.Fields
(
new ModelField("id", ModelFieldType.Int),
new ModelField("company"),
new ModelField("price", ModelFieldType.Float),
new ModelField("change", ModelFieldType.Float),
new ModelField("pctChange", ModelFieldType.Float),
new ModelField("lastChange", ModelFieldType.Date)
)
)
)
.ColumnModel
(
Html.X().Column().Text("Company").DataIndex("company").Flex(1),
Html.X().Column().Text("Price").DataIndex("price").Width(75).Renderer(RendererFormat.UsMoney),
Html.X().Column().Text("Change").DataIndex("change").Width(75),
Html.X().Column().Text("Change").DataIndex("pctChange").Width(75),
Html.X().DateColumn().Text("Last Updated").DataIndex("lastChange").Width(85).Format("H:mm:ss")
)
.Listeners(l =>
{
l.SelectionChange.Handler = "if (selected[0]) { this.next('propertygrid').setSource(selected[0].data); }";
})

,
Html.X().PropertyGrid().Editable(false).SortableCo lumns(false).Flex(2).Title("Properties")
.Source(s =>
{
PropertyGridParameter pgpString = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Company", Name = "company" });
PropertyGridParameter pgpBoolean = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Price", Name = "price" });
PropertyGridParameter pgpSep = new PropertyGridParameter("separator", "");
PropertyGridParameter pgpDate = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Change", Name = "change" });
PropertyGridParameter pgpInt = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Percent Change", Name = "pctChange" });
PropertyGridParameter pgpFloat = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Last Change", Name = "lastChange" });

s.AddRange(new PropertyGridParameter[] { pgpString, pgpBoolean, pgpSep, pgpDate, pgpInt, pgpFloat });
})
.View
(
Html.X().GridView().GetRowClass(grc => grc.Handler = "return record.data.name == 'separator' ? 'my-class' : '';"))
)
)
)


An GetObjects is


public ActionResult GetObjects()
{
DateTime now = DateTime.Now;

var myObjects = new object[]
{
new object[] { 1, "3m Co", 71.72, 0.02, 0.03, now },
new object[] { 2, "Alcoa Inc", 29.01, 0.42, 1.47, now },
new object[] { 3, "Altria Group Inc", 83.81, 0.28, 0.34, now },
new object[] { 4, "American Express Company", 52.55, 0.01, 0.02, now },
new object[] { 5, "American International Group, Inc.", 64.13, 0.31, 0.49, now },
new object[] { 6, "AT&T Inc.", 31.61, -0.48, -1.54, now },
new object[] { 7, "Boeing Co.", 75.43, 0.53, 0.71, now },
new object[] { 8, "Caterpillar Inc.", 67.27, 0.92, 1.39, now },
new object[] { 9, "Citigroup, Inc.", 49.37, 0.02, 0.04, now },
new object[] { 10, "E.I. du Pont de Nemours and Company", 40.48, 0.51, 1.28, now },
new object[] { 11, "Exxon Mobil Corp", 68.1, -0.43, -0.64, now },
new object[] { 12, "General Electric Company", 34.14, -0.08, -0.23, now },
new object[] { 13, "General Motors Corporation", 30.27, 1.09, 3.74, now },
new object[] { 14, "Hewlett-Packard Co.", 36.53, -0.03, -0.08, now },
new object[] { 15, "Honeywell Intl Inc", 38.77, 0.05, 0.13, now },
new object[] { 16, "Intel Corporation", 19.88, 0.31, 1.58, now },
new object[] { 17, "International Business Machines", 81.41, 0.44, 0.54, now },
new object[] { 18, "Johnson & Johnson", 64.72, 0.06, 0.09, now },
new object[] { 19, "JP Morgan & Chase & Co", 45.73, 0.07, 0.15, now },
new object[] { 20, "McDonald\"s Corporation", 36.76, 0.86, 2.40, now },
new object[] { 21, "Merck & Co., Inc.", 40.96, 0.41, 1.01, now },
new object[] { 22, "Microsoft Corporation", 25.84, 0.14, 0.54, now },
new object[] { 23, "Pfizer Inc", 27.96, 0.4, 1.45, now },
new object[] { 24, "The Coca-Cola Company", 45.07, 0.26, 0.58, now },
new object[] { 25, "The Home Depot, Inc.", 34.64, 0.35, 1.02, now },
new object[] { 26, "The Procter & Gamble Company", 61.91, 0.01, 0.02, now },
new object[] { 27, "United Technologies Corporation", 63.26, 0.55, 0.88, now },
new object[] { 28, "Verizon Communications", 35.57, 0.39, 1.11, now },
new object[] { 29, "Wal-Mart Stores, Inc.", 45.45, 0.73, 1.63, now }
};
return this.Store(myObjects);
}

Daniil
Oct 20, 2015, 12:23 PM
Before select change occurs separator isn't painted well.

Before you've found out that there is x-grid-row, but not x-grid3-row. I don't see you've applied this change for CSS rules.

Also were you able to find x-props-grid while inspecting HTML elements? As far as I can see it has been renamed to x-property-grid since v1. Just to clarify - I didn't know that, but found out it by inspecting HTML elements.

So, with the changes I mentioned above, the resulting CSS rules are:

.x-property-grid .x-grid-body .x-grid-row.my-class td {
background-color: Red !important;
border-right-color: Red;
}

.x-property-grid .x-grid-row.my-class .x-grid-td-name .x-grid-cell-inner {
background-image: none !important;
}

They appear to be working.


After select change next problem is (unwanted) appearance of id

Okay, from this post (http://forums.ext.net/showthread.php?60239-Showing-selected-gridpanel-row-in-property-grid&p=275537&viewfull=1#post275537) in another thread I remember that removing the id property from selected[0].data is not appropriate for your scenario, because you need the id later dealing with the PropertyGrid.

I have an idea on a possible solution. Please give it a try.

Html.X().GridView().GetRowClass(grc => grc.Fn = "getRowClass"))

var getRowClass = function (record, rowIndex, rowParams, store) {
var cls = "";

if (record.data.name === "separator") {
cls = "my-class";
} else if (record.data.name === "id") {
cls = "x-hidden";
}

return cls;
};

By the way, do you really need a presence of id in the PropertyGrid (not visually, but in the source)? Please clarify how did you remove an id from selected[0].data? I think the data should be cloned first.

var data = Ext.clone(selected[0].data);
delete data.id;

In this was the id will stay in a GridPanel's record.


(unwanted) disappearing of separator

I think a separator is going to be be injected manually. But... there is actually no guarantee in the properties order (http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order). So, there is a possibility the approach fails. Still you can try to inject a separator property manually.

There is also an alternative approach - adding a wider bottom border for the Price property. But with this approach I don't see a way to add a text label for such a separator.

Example

<!DOCTYPE html>
<html>
<head>
<title>Ext.Net.MVC v2 Example</title>

<style>
.x-property-grid .x-grid-body .x-grid-row.my-separator td {
border-bottom-color: red;
border-bottom-width: 10px;
}
</style>

<script>
var getRowClass = function (record, rowIndex, rowParams, store) {
var cls = "";

if (record.data.name === "price") {
cls = "my-separator";
}

return cls;
};

var onSelectionChange = function (selModel, selected) {
var data;

if (selected[0]) {
data = Ext.clone(selected[0].data);
delete data.id;
this.next('propertygrid').setSource(data);
}
};
</script>

</head>
<body>
@Html.X().ResourceManager()

@(Html.X().Panel()
.LayoutConfig(new HBoxLayoutConfig { Align = HBoxAlign.Stretch })
.Items
(
Html.X().GridPanel()
.Title("GridPanel with PropertyGrid")
.Flex(4)
.Store
(
Html.X().Store()
.AutoLoad(true)
.Proxy(Html.X().AjaxProxy()
.Url(Url.Action("GetObjects"))
.Reader(Html.X().ArrayReader()
.Root("data"))
)
.Model
(
Html.X().Model()
.Fields
(
new ModelField("id", ModelFieldType.Int),
new ModelField("company"),
new ModelField("price", ModelFieldType.Float),
new ModelField("change", ModelFieldType.Float),
new ModelField("pctChange", ModelFieldType.Float),
new ModelField("lastChange", ModelFieldType.Date)
)
)
)
.ColumnModel
(
Html.X().Column().Text("Company").DataIndex("company").Flex(1),
Html.X().Column().Text("Price").DataIndex("price").Width(75).Renderer(RendererFormat.UsMoney),
Html.X().Column().Text("Change").DataIndex("change").Width(75),
Html.X().Column().Text("Change").DataIndex("pctChange").Width(75),
Html.X().DateColumn().Text("Last Updated").DataIndex("lastChange").Width(85).Format("H:mm:ss")
)
.Listeners(l =>
{
l.SelectionChange.Fn = "onSelectionChange";
}),

Html.X().PropertyGrid()
.Editable(false)
.SortableColumns(false)
.Flex(1)
.Title("Properties")
.Source(s =>
{
PropertyGridParameter pgpString = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Company", Name = "company" });
PropertyGridParameter pgpBoolean = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Price", Name = "price" });
PropertyGridParameter pgpDate = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Change", Name = "change" });
PropertyGridParameter pgpInt = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Percent Change", Name = "pctChange" });
PropertyGridParameter pgpFloat = new PropertyGridParameter(new PropertyGridParameter.Config() { DisplayName = "Last Change", Name = "lastChange" });

s.AddRange(new PropertyGridParameter[] { pgpString, pgpBoolean, pgpDate, pgpInt, pgpFloat });
})
.View
(
Html.X().GridView().GetRowClass(grc => grc.Fn = "getRowClass"))
)
)
)
</body>
</html>


Meanwhile, will you need expanding/collapsing of groups?

ingbabic
Oct 21, 2015, 12:36 PM
Before you've found out that there is x-grid-row, but not x-grid3-row. I don't see you've applied this change for CSS rules.

Also were you able to find x-props-grid while inspecting HTML elements? As far as I can see it has been renamed to x-property-grid since v1. Just to clarify - I didn't know that, but found out it by inspecting HTML elements.

Well it's true, I don't understand how these things (about CSS and so) are working, thanks for explanation. Of course I don't want that separator is red and I struggled to change it but no matter what color I put I am not satisfied with the appearance. Closest color to what I want is #f0f0f0, but appearance is flat. Also in different theme (Access for example) it doesn't look well. I don't know what to do.

Both solutions what you've proposed for hiding ID are working, thanks. However my case is little more complicated. In property grid I would like to have only those fields which are configured (as in data I have more then ID which I would not like to show). Fields which I want to show in property grid are configured and I read that configuration and presenting it in UI (some fields in grid, much more in property grid, but there are some system fields, which aren't needed in UI). Back in time when I was working in desktop you could configure property grid to show only what you want, not more, not less. I try to explain in pseudo code what would be cool :)


if (config != null){
foreach(field in data)
if (config.contains(field))
fillOnlyValue(field,data[field])
} else {
createPropertyGridFromScratch(data);
}




Meanwhile, will you need expanding/collapsing of groups?
Well that would be perfect. Actually our desktop solution which we are porting to web has that feature...

Daniil
Oct 22, 2015, 7:10 AM
Well that would be perfect. Actually our desktop solution which we are porting to web has that feature...

I am afraid we won't get it working with a PropertyGrid. It looks like it is time to switch to a GridPanel:
http://forums.ext.net/showthread.php?60239&p=275547&viewfull=1#post275547

ingbabic
Oct 22, 2015, 2:58 PM
Well, OK. I made a sample and it works. Only what I want to ask you more, is there a better way to do this, because it seems that it reloading of grid takes more time then property grid.

View:


@Html.X().ResourceManager()

@(
Html.X().Panel().Layout(LayoutType.HBox).LayoutCon fig(new HBoxLayoutConfig { Align = HBoxAlign.Stretch })
.Items
(
Html.X().GridPanel().ID("mainGrid").Title("GridPanel with PropertyGrid").Flex(8)
.Store
(
Html.X().Store().AutoLoad(true).Proxy(Html.X().Aja xProxy().Url(Url.Action("GetObjects")).Reader(Html.X().ArrayReader().Root("data")))
.Model
(
Html.X().Model()
.Fields
(
new ModelField("id", ModelFieldType.Int),
new ModelField("company"),
new ModelField("price", ModelFieldType.Float),
new ModelField("change", ModelFieldType.Float),
new ModelField("pctChange", ModelFieldType.Float),
new ModelField("lastChange", ModelFieldType.Date)
)
)
)
.ColumnModel
(
Html.X().Column().Text("Company").DataIndex("company").Flex(1),
Html.X().Column().Text("Price").DataIndex("price").Width(75).Renderer(RendererFormat.UsMoney),
Html.X().Column().Text("Change").DataIndex("change").Width(75),
Html.X().Column().Text("Change").DataIndex("pctChange").Width(75),
Html.X().DateColumn().Text("Last Updated").DataIndex("lastChange").Width(85).Format("H:mm:ss")
)
.Listeners(l =>
{
l.SelectionChange.Handler = "if (selected[0]) { this.next('grid').getStore().reload(); }";
})

,
Html.X().GridPanel().Title("Properties").Flex(2)
.Store
(
Html.X().Store().GroupField("area")
.Model
(
Html.X().Model()
.Fields
(
new ModelField("area"),
new ModelField("fieldName"),
new ModelField("fieldValue")
)
)
.Proxy(Html.X().AjaxProxy().Url(Url.Action("FillProperties")).Reader(Html.X().JsonReader().Root("data")))
.Parameters
(
Html.X().StoreParameter().Name("selectedRows").Value("Ext.encode(App.mainGrid.getRowsValues({selectedOnl y: true}))").Mode(ParameterMode.Raw)
)

)
.ColumnModel
(
Html.X().Column().Text("Name").DataIndex("fieldName").Flex(1).MenuDisabled(true).Sortable(false),
Html.X().Column().Text("Value").DataIndex("fieldValue").Flex(1).MenuDisabled(true).Sortable(false),
Html.X().Column().DataIndex("area").Hidden(true)
)
.Features(Html.X().Grouping().EnableGroupingMenu(f alse).GroupHeaderTplString("{name}"))
)
)


Controller:


public ActionResult FillProperties(string selectedRows)
{
List<Dictionary<string, string>> values = new List<Dictionary<string, string>>()
{
new Dictionary<string, string>() { { "area", "General data" }, { "fieldName", "Company" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "General data" }, { "fieldName", "Price" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "Statistical data" }, { "fieldName", "Change" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "Statistical data" }, { "fieldName", "Percent change" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "Statistical data" }, { "fieldName", "Last Updated" }, { "fieldValue", "" } }
};

if (selectedRows != "[]")
{
List<Dictionary<string, string>> rows = JSON.Deserialize<List<Dictionary<string, string>>>(selectedRows);
Dictionary<string, string> selected = rows[0];
values.Find(i => i.ContainsValue("Company"))["fieldValue"] = selected["company"];
values.Find(i => i.ContainsValue("Price"))["fieldValue"] = selected["price"];
values.Find(i => i.ContainsValue("Change"))["fieldValue"] = selected["change"];
values.Find(i => i.ContainsValue("Percent change"))["fieldValue"] = selected["pctChange"];
values.Find(i => i.ContainsValue("Last Updated"))["fieldValue"] = selected["lastChange"];
}
return this.Store(values);
}

Daniil
Oct 22, 2015, 3:06 PM
Well, with a PropertyGrid you were loading data locally (exclusively on client side), but now with a GridPanel you are loading data remotely with a request to server. Yes, it is more slowly.

There is a Store's loadData() method that you can use to load data locally to a GridPanel's Store.
http://docs.sencha.com/extjs/5.1/5.1.1-apidocs/#!/api/Ext.data.Store-method-loadData

ingbabic
Oct 23, 2015, 3:09 PM
Finally, I think I came to final solution. In case anyone need this, this would it be:
View:


<script>
var refreshPropertyGrid = function (selModel, selected) {

// all records with getRange()
var records = App.props.getStore().getRange();

// iteration of the store
Ext.each(records, function (item, idx) {
// item.get to access a field in the record
item.beginEdit();
item.data.fieldValue = selected[0].data[item.data.fieldName];
item.endEdit();
item.commit();
});
};
</script>

@Html.X().ResourceManager()

@(
Html.X().Panel().Layout(LayoutType.HBox).LayoutCon fig(new HBoxLayoutConfig { Align = HBoxAlign.Stretch })
.Items
(
Html.X().GridPanel().ID("mainGrid").Title("GridPanel with PropertyGrid").Flex(8)
.Store
(
Html.X().Store().AutoLoad(true).Proxy(Html.X().Aja xProxy().Url(Url.Action("GetObjects")).Reader(Html.X().ArrayReader().Root("data")))
.Model
(
Html.X().Model()
.Fields
(
new ModelField("id", ModelFieldType.Int),
new ModelField("company"),
new ModelField("price", ModelFieldType.Float),
new ModelField("change", ModelFieldType.Float),
new ModelField("pctChange", ModelFieldType.Float),
new ModelField("lastChange", ModelFieldType.Date)
)
)
)
.ColumnModel
(
Html.X().Column().Text("Company").DataIndex("company").Flex(1),
Html.X().Column().Text("Price").DataIndex("price").Width(75).Renderer(RendererFormat.UsMoney),
Html.X().Column().Text("Change").DataIndex("change").Width(75),
Html.X().Column().Text("Change").DataIndex("pctChange").Width(75),
Html.X().DateColumn().Text("Last Updated").DataIndex("lastChange").Width(85).Format("H:mm:ss")
)
.Listeners(l =>
{
l.SelectionChange.Fn = "refreshPropertyGrid";
})

,
Html.X().GridPanel().ID("props").Title("Properties").Flex(2)
.Store
(
Html.X().Store().GroupField("area")
.Model
(
Html.X().Model()
.Fields
(
new ModelField("area"),
new ModelField("fieldName"),
new ModelField("fieldLabel"),
new ModelField("fieldValue")
)
)
.Proxy(Html.X().AjaxProxy().Url(Url.Action("FillProperties")).Reader(Html.X().JsonReader().Root("data")))
)
.ColumnModel
(
Html.X().Column().Text("Name").DataIndex("fieldLabel").Flex(1).MenuDisabled(true).Sortable(false),
Html.X().Column().Text("Value").DataIndex("fieldValue").Flex(1).MenuDisabled(true).Sortable(false),
Html.X().Column().DataIndex("area").Hidden(true),
Html.X().Column().DataIndex("fieldName").Hidden(true)
)
.Features(Html.X().Grouping().EnableGroupingMenu(f alse).GroupHeaderTplString("{name}"))
)
)


Controller


public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}

public ActionResult GetObjects()
{
DateTime now = DateTime.Now;

var myObjects = new object[]
{
new object[] { 1, "3m Co", 71.72, 0.02, 0.03, now },
new object[] { 2, "Alcoa Inc", 29.01, 0.42, 1.47, now },
new object[] { 3, "Altria Group Inc", 83.81, 0.28, 0.34, now },
new object[] { 4, "American Express Company", 52.55, 0.01, 0.02, now },
new object[] { 5, "American International Group, Inc.", 64.13, 0.31, 0.49, now },
new object[] { 6, "AT&T Inc.", 31.61, -0.48, -1.54, now },
new object[] { 7, "Boeing Co.", 75.43, 0.53, 0.71, now },
new object[] { 8, "Caterpillar Inc.", 67.27, 0.92, 1.39, now },
new object[] { 9, "Citigroup, Inc.", 49.37, 0.02, 0.04, now },
new object[] { 10, "E.I. du Pont de Nemours and Company", 40.48, 0.51, 1.28, now },
new object[] { 11, "Exxon Mobil Corp", 68.1, -0.43, -0.64, now },
new object[] { 12, "General Electric Company", 34.14, -0.08, -0.23, now },
new object[] { 13, "General Motors Corporation", 30.27, 1.09, 3.74, now },
new object[] { 14, "Hewlett-Packard Co.", 36.53, -0.03, -0.08, now },
new object[] { 15, "Honeywell Intl Inc", 38.77, 0.05, 0.13, now },
new object[] { 16, "Intel Corporation", 19.88, 0.31, 1.58, now },
new object[] { 17, "International Business Machines", 81.41, 0.44, 0.54, now },
new object[] { 18, "Johnson & Johnson", 64.72, 0.06, 0.09, now },
new object[] { 19, "JP Morgan & Chase & Co", 45.73, 0.07, 0.15, now },
new object[] { 20, "McDonald\"s Corporation", 36.76, 0.86, 2.40, now },
new object[] { 21, "Merck & Co., Inc.", 40.96, 0.41, 1.01, now },
new object[] { 22, "Microsoft Corporation", 25.84, 0.14, 0.54, now },
new object[] { 23, "Pfizer Inc", 27.96, 0.4, 1.45, now },
new object[] { 24, "The Coca-Cola Company", 45.07, 0.26, 0.58, now },
new object[] { 25, "The Home Depot, Inc.", 34.64, 0.35, 1.02, now },
new object[] { 26, "The Procter & Gamble Company", 61.91, 0.01, 0.02, now },
new object[] { 27, "United Technologies Corporation", 63.26, 0.55, 0.88, now },
new object[] { 28, "Verizon Communications", 35.57, 0.39, 1.11, now },
new object[] { 29, "Wal-Mart Stores, Inc.", 45.45, 0.73, 1.63, now }
};
return this.Store(myObjects);
}

public ActionResult FillProperties()
{
List<Dictionary<string, string>> values = new List<Dictionary<string, string>>()
{
new Dictionary<string, string>() { { "area", "General data" }, { "fieldName", "company" }, { "fieldLabel", "Company" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "General data" }, { "fieldName", "price" }, { "fieldLabel", "Price" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "Statistical data" }, { "fieldName", "change" }, { "fieldLabel", "Change" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "Statistical data" }, { "fieldName", "pctChange" }, { "fieldLabel", "Percent change" }, { "fieldValue", "" } },
new Dictionary<string, string>() { { "area", "Statistical data" }, { "fieldName", "lastChange" }, { "fieldLabel", "Last Updated" }, { "fieldValue", "" } }
};

return this.Store(values);
}
}


Danill, please check if something could be made better (i'm not sure about refreshPropertyGrid, I've got this idea from there (https://gist.github.com/enovision/5756018)). Thanks for help. Both this and that (http://forums.ext.net/showthread.php?60239-Showing-selected-gridpanel-row-in-property-grid) thread could be closed. Just please don't forget to check refreshPropertyGrid :)

Daniil
Oct 25, 2015, 7:41 PM
Do you think that item.beginEdit(); and item.endEdit(); calls are required? I used to think that it is only required if you use a record's .set() call.

ingbabic
Oct 26, 2015, 7:39 AM
Indeed they're not needed (checked).

Daniil
Oct 26, 2015, 7:47 AM
Thank you for confirming. Now I don't quite have anything to suggest what might be improved:)

ingbabic
Oct 26, 2015, 9:13 AM
Hmm, I moved this solution to my project and it's still slowwww :(. I mean setSource from property grid worked quite faster. In my property grid I have 39 properties. It takes 2.1 seconds to move from one row to another. :((

Daniil
Oct 26, 2015, 9:44 AM
I quite hope there is a way to improve performance, but I need a test case to reproduce. Could you, please, provide?

ingbabic
Oct 27, 2015, 9:28 AM
This sample is even more extreme (although I don't understand why). Selection change takes more then 5 seconds! I played a bit with number of columns and only if I have around 10, performance is near to decent.

Controller:


public class PropertyGridController : Controller
{
const int colNumber = 40;
const int colSep = 10;
// GET: PropertyGrid
public ActionResult Index()
{
ViewBag.colNum = colNumber;
return View();
}

public ActionResult GetObjects()
{
var myObjects = new object[100];
for (int i = 0; i < 100; i++)
{
var properties = new object[40];
for (int j = 0; j < colNumber; j++)
{
properties[j] = ((i + 1) * 100 + (j + 1)).ToString();
}
myObjects[i] = properties;
}
return this.Store(myObjects);
}

public ActionResult FillProperties()
{
List<Dictionary<string, string>> values = new List<Dictionary<string, string>>();

string area = null;
for (int i = 0; i < colNumber; i++)
{
Dictionary<string, string> attribute = new Dictionary<string, string>();
if (i % colSep == 0)
area = String.Format("Attributes from {0} to {1}", i, i + colSep);

attribute.Add("area", area);
attribute.Add("fieldName", String.Format("attr_{0}", i));
attribute.Add("fieldLabel", String.Format("Attribute{0}", i));
attribute.Add("fieldValue", "");
values.Add(attribute);
}

return this.Store(values);
}
}


View:



<script>
var refreshPropertyGrid = function (selModel, selected) {

// all records with getRange()
var records = App.props.getStore().getRange();

// iteration of the store
Ext.each(records, function (item, idx) {
// item.get to access a field in the record
item.data.fieldValue = selected[0].data[item.data.fieldName];
item.commit();
});
};
</script>

@Html.X().ResourceManager()

@(
Html.X().Panel().Layout(LayoutType.HBox).LayoutCon fig(new HBoxLayoutConfig { Align = HBoxAlign.Stretch })
.Items
(
Html.X().GridPanel().Title("GridPanel with PropertyGrid").Flex(8)
.Store
(
Html.X().Store().AutoLoad(true).Proxy(Html.X().Aja xProxy().Url(Url.Action("GetObjects")).Reader(Html.X().ArrayReader().Root("data")))
.Model
(
Html.X().Model()
.Fields(f =>
{
for (int i = 0; i < ViewBag.colNum; i++)
{
ModelField mf = new ModelField(String.Format("attr_{0}", i));
f.Add(mf);
}

})
)
)
.ColumnModel(c => {
Random r = new Random();
for (int i = 0; i < ViewBag.colNum; i++)
{
Column column = new Column();
column.Text = String.Format("Attribute{0}", i);
column.DataIndex = String.Format("attr_{0}", i);
column.Flex = 1;
if (r.Next(100) > 30)
column.Hidden = true;
c.Columns.Add(column);
}
})
.Listeners(l =>
{
l.SelectionChange.Fn = "refreshPropertyGrid";
})

,
Html.X().GridPanel().ID("props").Title("Properties").Flex(2)
.Store
(
Html.X().Store().GroupField("area")
.Model
(
Html.X().Model()
.Fields
(
new ModelField("area"),
new ModelField("fieldName"),
new ModelField("fieldLabel"),
new ModelField("fieldValue")
)
)
.Proxy(Html.X().AjaxProxy().Url(Url.Action("FillProperties")).Reader(Html.X().JsonReader().Root("data")))
)
.ColumnModel
(
Html.X().Column().Text("Name").DataIndex("fieldLabel").Flex(1).MenuDisabled(true).Sortable(false),
Html.X().Column().Text("Value").DataIndex("fieldValue").Flex(1).MenuDisabled(true).Sortable(false),
Html.X().Column().DataIndex("area").Hidden(true),
Html.X().Column().DataIndex("fieldName").Hidden(true)
)
.Features(Html.X().Grouping().EnableGroupingMenu(f alse).GroupHeaderTplString("{name}"))
)
)

Daniil
Oct 27, 2015, 12:51 PM
Thank you for the test case.

Please use:

var refreshPropertyGrid = function (selModel, selected) {
// all records with getRange()
var records = App.props.getStore().getRange();

// iteration of the store
Ext.each(records, function (item, idx) {
// item.get to access a field in the record
item.data.fieldValue = selected[0].data[item.data.fieldName];
});

App.props.getView().refresh();
};

ingbabic
Oct 27, 2015, 1:43 PM
Wow :)
Thanks