I have a datatable with many columns, like so;
Name | Age | Foo | Bar | Etc..
Joe | 30 | foo | bar | Etc..
I need to now get this datatable into just two columns consisting of just the headers followed by their values, like so;
Header | Value
Name | Joe
Age | 30
Foo | foo
Etc... | etc..
This is so that a DataBinder can access it easily when the data is bound.
How can this be done, and do I need to do this at all?
EDIT: Including example code
asp.net
<div class="itemDetail col-s">
<div class="itemDetailLabel">
<%# DataBinder.Eval(Container.DataItem, "Caption")%>
</div>
<div class="itemDetailValue">
<%# If(DataBinder.Eval(Container.DataItem, "UIValue") Is Nothing OrElse String.IsNullOrEmpty(DataBinder.Eval(Container.DataItem, "UIValue").ToString()), " ", DataBinder.Eval(Container.DataItem, "UIValue")) %>
</div>
</div>
vb.net
Dim oldDataTable As DataTable = DataSource ''Which is a datatable of a single row
Dim newDataTable As New DataTable
newDataTable.Columns.Add("Caption")
newDataTable.Columns.Add("UIValue")
''Change the single row into multiple rows
fooControl.DataSource = newDataTable
fooControl.DataBind()
EDIT2: So for those that are still learning like me, this is called transposing. Thanks for #gofal3 for pointing it out
You have to transpose the DataTable. As far as I know there is no built in method, but you have to write your own code to do so.
But there are a lot of examples how other did it. eg: https://www.codeproject.com/Articles/44274/Transpose-a-DataTable-using-C or Transpose a datatable
Related
I would to make the field descriptions and label texts in my pages multi-lingual. Originally they are in English and I could let the user translate them through Google Translate. In order to avoid translation errors I would like to implement a translation data model that contains
FieldDisplayName / LabelText
FieldDisplayName_DE
FieldDisplayName_FR
FieldDisplayName_IT
etc.
All the pages contain a page header fragment that contains a menu button, searchbox etc. like in the Starter App template. I am planning on integrating a dropdown widget in the page header that allows to choose between the languages (DE,EN,FR,IT,...). Is it possible to bind the display name to the user's selection? How would I have to implement that?
The easiest way (to implement/use/maintain) that would provide highest possible translation quality will be introducing Translation data model with the following structure:
+----+--------+------------+------------+------------+-----+
| Id | Locale | FirstName | LastName | Age | ... |
+----+--------+------------+------------+------------+-----+
| 1 | EN | First name | Last name | Age | ... |
+----+--------+------------+------------+------------+-----+
| 2 | RU | Имя | Фамилия | Возраст | ... |
+----+--------+------------+------------+------------+-----+
| 3 | DE | Voornaam | Achternaam | Leeftijd | ... |
+----+--------+------------+------------+------------+-----+
| 4 | ... | ... | .... | ... | ... |
+----+--------+------------+------------+------------+-----+
In this model every column represents unique label within your app and every row represents labels's translations for supported languages. This model can be easily used in label bindings:
#datasources.UserTranslations.item.FieldNameToTranslate
Maintaining these translation will be easy as well, just drag and drop editable table on UI.
Here is a query script for the UserTranslations datasource:
// Assuming that you already have robust user settings implementation.
var userSettings = getUserSettings_();
var query = app.models.Translation.newQuery();
query.filters.Locale._equals = userSettings.Locale;
return query.run();
Radically different implementation will be
Introducing Calculated Model with the same set of fields as in the previous approach
Using Model Metadata API to extract display names from the model's fields
Translate fields using Translate API
Populate calculated model record with translated values
Here is super high level server pseudo script for that flow:
var userLocale = getUserLocaleFromUserSettings();
var fieldsDisplayNames = getFieldsDisplayNames(app.models.Translation);
var translations = translate(fieldsDisplayNames, 'en', userLocale);
var record = app.models.Translation.newRecord();
mapRecordFieldsToTranslations(record, translations);
return [record];
After some trials a translation model turned out to be too laggy for my demands. Therefore I have hardcoded the binding expression into the labels I want to translate. The binding expression looks a little bit like this:
(#pages.UserSettings.LanguageDropdown.value == 'EN') ? 'Contact' : 'Kontakt'
I have some data in Application Insights Analytics that has a dynamic object as a property of custom dimensions. For example:
| timestamp | name | customDimensions | etc |
|-------------------------|---------|----------------------------------|-----|
| 2017-09-11T19:56:20.000 | Spinner | { | ... |
MyCustomDimension: "hi"
Properties:
context: "ABC"
userMessage: "Some other"
}
Does that make sense? So a key/value pair inside of customDimensions.
I'm trying to bring up the context property to be a proper column in the results. So expected would be :
| timestamp | name | customDimensions | context| etc |
|-------------------------|---------|----------------------------------|--------|-----|
| 2017-09-11T19:56:20.000 | Spinner | { | ABC | ...
MyCustomDimension: "hi"
Properties:
context: "ABC"
userMessage: "Some other"
}
I've tried this:
customEvents | where name == "Spinner" | extend Context = customDimensions.Properties["context"]
and this:
customEvents | where name == "Spinner" | extend Context = customDimensions.Properties.context
but neither seem to work. They give me a column at the end named "Context" but the column is empty - no values.
Any ideas?
EDIT:
Added a picture for clarifying the format of the data:
edited to working answer:
customEvents
| where name == "Spinner"
| extend Properties = todynamic(tostring(customDimensions.Properties))
| extend Context = Properties.context
you need an extra tostring and todynamic in here to get what you expect (and what i expected!)
the explanation i was given:
Dynamic field "promises" you the upper/outer level of key / value access (this is how you access customDimensions.Properties).
Accessing internal structure of that json depends on the exact format of customDimensions.Properties content. It doesn’t have to be json by itself. Even if it looks like a well structured json, it still may be just a string that is not exactly well formatted json.
So basically, it by default won't attempt to parse strings inside of a dynamic/json block because they don't want to spend a lot of time possibly trying and failing to convert nested content to json infinitely.
I still think that extra tostring shouldn't be required inside there, since todynamic should already be allowing both string and dynamic in validly, so i'm checking to see if the team that owns the query stuff can make that step better.
Thanks sooo much.. just to expand on the answer from John. We needed to graph duration of end-points using custom events. This query made it so we could specify the duration as our Y-axis in the chart:
customEvents
| extend Properties = todynamic(tostring(customDimensions.Properties))
| extend duration = todouble(todecimal(Properties.duration))
| project timestamp, name, duration
I have a dropdownlist populating list of values in it in page_load .
I want to select a specific value
Me.DropDownList_LocalOfficeAssignment.SelectedValue = ct.LocalOfficeName
Me.DropDownList_LocalOfficeAssignment has list of values.
Problem is: It always pointing to first item.
i tried this
For Each item As ListItem In Me.DropDownList_LocalOfficeAssignment.Items
If item.Equals(ct.LocalOfficeName) Then
item.Selected = True
Exit For
End If
Next
DV.Dispose()
still pointing to the first item. i debugged, it should point to the last item.
ct.localoffice is containing the last item in the list. This is how i am populating the dropdown :
Dim DV As DataView = New DataView(CacheVariable.States.Tables(0))
Dim DRV As DataRowView
Me.DropDownList_LocalOfficeAssignment.Items.Clear()
DV = New DataView(CacheVariable.LocalOffice.Tables(0))
If DV.Count > 0 Then
For Each DRV In DV
Me.DropDownList_LocalOfficeAssignment.Items.Add(New ListItem(DRV("Name"), DRV("LocalOfficeID").ToString))
Next
End If
Based on lengthy comments on the question...
You're looking for the wrong value when you try to set the SelectedValue. Take a look at how you create your ListItems:
Me.DropDownList_LocalOfficeAssignment.Items.Add(New ListItem(DRV("Name"), DRV("LocalOfficeID").ToString))
When creating a ListItem, you pass it both its display text and its underlying value. In this case, you're setting them as:
Display Text = DRV("Name")
Underlying Value = DRV("LocalOfficeID")
According to your comments, the sample data looks something like this:
LocalOfficeID | Name
--------------------
1 | abc
2 | def
3 | xyz
Then, when you try to manually set the SelectedValue, you're passing it the wrong value. You're essentially trying to do this:
DropDownList_LocalOfficeAssignment.SelectedValue = "xyz"
None of the Value properties on the ListItems are "xyz". They're "1", "2", and "3". In order to set the SelectedValue, you need this:
DropDownList_LocalOfficeAssignment.SelectedValue = "3"
So this line needs to change:
Me.DropDownList_LocalOfficeAssignment.SelectedValue = ct.LocalOfficeName
On your ct object you need to get the identifier for the object, not its display name. Probably something like this (though without knowing what ct is I can't be certain):
DropDownList_LocalOfficeAssignment.SelectedValue = ct.ID
If you don't have the identifier, then you can find it on the DropDownList by searching for the display name. Something like this should work, though there may be a more elegant way to do it:
DropDownList_LocalOfficeAssignment.SelectedIndex = DropDownList_LocalOfficeAssignment.Items.IndexOf(DropDownList_LocalOfficeAssignment.Items.FindByText(ct.LocalOfficeName))
Using the identifier would be much cleaner, though.
This is usually because the DropDownList does DataBind() after you set the SelectedValue. Do you have the DropDownList.DataSourceID property set? Are you calling DataBind() later in the page lifecycle?
I don't know if the follow code snippet intend to work in this way, because sometimes we "as developers" try automate creation of data display control where number of fields are uncontrolled and with similar data-binding, so before I review the application some guys left this :
Under ActiveReport_ReportStart() event :
for (Ind = 1; Ind <=CM.Length; Ind++) {
if (Ind == 1) {
Left = ((Line)rpt.Sections["PageHeader"].Controls["lnH8"]).Left + 0.05f;
} else if (Ind == 2) {
Left = ((Line)rpt.Sections["PageHeader"].Controls["lnH9"]).Left + 0.05f;
} else if (Ind == 3) {
Left = ((Line)rpt.Sections["PageHeader"].Controls["lnH10"]).Left + 0.05f;
}
TextBox TB = new TextBox();
TB.Size = ((Label)rpt.Sections["PageHeader"].Controls["tbColorway1"]).Size;
TB.Font = ((Label)rpt.Sections["PageHeader"].Controls["tbColorway1"]).Font;
TB.Width = ((Label)rpt.Sections["PageHeader"].Controls["tbColorway1"]).Width;
TB.Height = ((Label)rpt.Sections["PageHeader"].Controls["tbColorway1"]).Height;
TB.VerticalAlignment = VerticalTextAlignment.Top;
TB.Location = new System.Drawing.PointF(Left, ((Label)rpt.Sections["PageHeader"].Controls["tbColorway1"]).Top);
TB.DataField = "ColorText" + Ind + ColorwayNumber;
rpt.Sections["Detail"].Controls.Add(TB);
It doesn't have compilation error when is previewed, also others fields that are not auto-generated are displayed correctly (ReporHeader, ReportFooter), but IMHO I think is better to replace this mechanism by a subreport inside the detail section, of course these fields have to be displayed in Detail section of the report. Anyways I would like to see some recommendations because if is possible to auto-generated textbox or labels in runtime I will have to explain to boss why this code was not working, and if I have to use subreports instead, I need to know how to pass parameter (at least I need to work with two parameters for generate another sql query for it) and what "event" is proper to put script into it..
After I discovered that most important problem is to get report format changes by how many field/textbox were added to report detail in runtime restricted by a sqlquery return value, for example :
Returned SQLQuery value = 4
10 fields generated for detailed row 1
6 fields for row 2
4 fields for row 3
Detail fields are bound to a SQL Store Procedure*
Report will supossed to be printed/showed in this way :
//Report Init
Page 1 :
|field 1|field 2|field 3|field 4|
------------------------------------------------------
row1 | valA1 | valA2 | valA3 | valA4 |
------------------------------------------------------
row2 | valB1 | valB2 | valB3 | valB4 |
------------------------------------------------------
row3 | valC1 | valC2 | valC3 | valC4 |
------------------------------------------------------
Page 2 :
|field 1|field 2|field 3|field 4|
------------------------------------------------------
row1 | valA5 | valA6 | valA7 | valA8 |
------------------------------------------------------
row2 | valB5 | valB6 |
------------------------------------------------------
row3
------------------------------------------------------
Page 3 :
|field 1|field 2|field 3|field 4|
------------------------------------------------------
row1 | valA9 | valA10|
------------------------------------------------------
row2
------------------------------------------------------
row3
------------------------------------------------------
//End of Report
Any help will be appreciated
Thank you so much
It is perfectly fine to dynamically create fields on a report at runtime. The creation of those fields do indeed need to be done in the reportstart event or earlier (i.e. before calling ActiveReport.Run).
However, you could place the same logic to dynamically create those fields in a subreport and pass a parameter too, but in general subreports do impose additional overhead (and an additional query in most cases) so I wouldn't use a subreport unless there is a compelling benefit. However, there is a walkthrough on passing parameters to a subreport here.
The only thing that looks suspect in your code is the following line:
TB.Location = new System.Drawing.PointF(Left, ((Label)rpt.Sections["PageHeader"].Controls["tbColorway1"]).Top);
You are using the Top value from a control in the PageHeader, but TB is in the Detail section. I can understand reusing the Left value, but reusing the Top value wouldn't be consistent across different sections (Top is it's vertical position from the top of the section containing the control)
Now, it sounds like sometimes these fields do not appear on the report. Some things you can verify to troubleshoot the problem:
Determine if there is a binding problem or a visual/location problem. TO do this, just give the textbox a border or a background color or something so you can see it even if there is no text (due to failed data binding).
Start logging out the position of each textbox and the datafield value to a log file. When you notice the problem, go back to the log and see if you can identify what triggers the problem (maybe a specific index, location or datafield value?).
Finally, make sure that the page size (determined by the system's default printer) is not changing and maybe cutting off one of your dynamically added textboxes.
I need to add a secondary (header) row to my ASP.NET GridView (which is already customized so I can access any part of the event lifecycle).
It's additional data that I want aligned with some of the columns.
It should look like this
Period | May | June | July | Aug -- Header
Basevalue | 3000 | 1500 | 1200 | 4000 -- EXTERNAL DATA
---------------------------------------
Item 1 | 100 | 200 | 300 | 400
Item 2 | 100 | 200 | 300 | 400
I managed to add a row with below code, but I am unable to create any kind of custom event where I could gain access and write my custom data into that cell. I tried the following, but during any event I could find (like OnRowCreated or PrepareControlHierarchy), it's either too late (after databinding) or the inner table is not initalized.
int rowIndex = 0;
GridViewRow secondHeaderRow = new GridViewRow(rowIndex, -1, DataControlRowType.Header, DataControlRowState.Normal);
secondHeaderRow.TableSection = TableRowSection.TableHeader;
foreach (DataControlField col in this.Columns)
{
TableHeaderCell cell = new TableHeaderCell();
cell.DataBinding += new EventHandler(OnHeaderCellDatabinding);
secondHeaderRow.Cells.Add(cell);
}
InnerTable.Rows.AddAt(rowIndex, secondHeaderRow);
How can I hook up to the GridView lifecycle to write in the header row?
hey niles,
we can use the caption to some HTML tags and start building the extra headers
please refer this link for your problem
CLICK HERE
hope it will help you
Try this. Merging columns in GridView/DataGrid header