Use a Computed Property as DisplayColumn in ASP.Net Dynamic Data? - asp.net

I am trying to display a 'Software Release' table in an asp.net dynamic data site. The Release table has a build number stored as three int fields (Major, Minor, Build). I'm using EntityFramework, so I have an EF model bound to my database schema. In my dynamic data site, I want the build number to show up as a single field (Major.Minor.Build) wherever the Release object is shown (particularly when it shows as a foreign key on pages for related objects). Since this 'computed column' is not a field in my database, there doesn't seem to be anyway to get the Dynamic-Data to recognize or display it. I can add a property to the Release object (since it is a partial class generated by EF), but Dynamic-Data won't recognize it, because it isn't a 'column'. I want to edit the Release as three separate fields (major, minor, build), but when it is displayed, I want it to show as a single field. The DynamicData framework doesn't seem to support composite fields, and it won't display/bind to properties on the object if they aren't in the EF model. How do I make the formatted version number property the default display value?

You can add an metadata class as you would when doing any dynamic data ui customization.
Then you create a UIHint in the metadata to tell the dynamic data what control to use for your custom object.
E.G.
[MetadataType(typeof(EMetadata))]
public partial class E{
public string RefNR {
get {
return "E" + this.EntryID.ToString().PadLeft(5, '0');
}
}
}
public partial class EMetadata {
[UIHint("Text")]
public object RefNR;
}

I'm not sure if you are binding to a DataTable/DataSet returned from the database, or if you are binding to a Release object itself. Nor which kind of control.
If you are binding to a DataSet/DataTable, simply change your SQL to return the version as one field:
SELECT table1.Major + '.' + table1.Minor + '.' + table1.Build AS Version ....
However, if you are binding to an object to, say, a DropDownList, I think that if you override the ToString method, it will become the Display value in the DropDownList:
Public Overrides Function ToString() As String
Return _major.ToString & '.' & _minor.ToString & '.' & _build.ToString
End Sub

Related

D365FO x++ syscomputedcolumn table name

How can you use the syscomputedcolumn class to retrieve a table or field name for an entity? this is fairly easy using virtual field entity postload method something like
public class SysDatabaseLogHeaderEntity extends common
{
public void postLoad()
{
super();
this.TableName = tableId2Name(this.table);
}
}
but there's a rumour that virtual fields won't be supported in upcoming synapse link for D 365 FnO so want to know how to do this with computed columns...
https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/data-entity-computed-columns-virtual-fields
SysComputedColumn is used to help create computed columns in views.
Supposing for some reason you want a column in which every row contains the string value "CustTable", you'd create create a method (AX 2012 syntax):
public static server string TableNameColumn()
{
return SysComputedColumn::returnLiteral(tableStr(CustTable));
}
and then you'd add a computed column to the view as outlined here: https://learn.microsoft.com/en-us/dynamicsax-2012/developer/walkthrough-add-a-computed-column-to-a-view
Note: hopefully this is a toy example, there is no reason to ever actually do this particular column. Or really any fully static columns.
View computed columns are essentially based on static server methods which return the SQL definition for the computed column, and then the SysComputedColumn class has a bunch of helper methods to let you build those SQL string statements without using specific implementation knowledge of the backend database such as column names.
A complete description is beyond the scope of this comment, but the big one you'll use is SysComputedColumn::returnField(view,datasource,field) which gets the specified field from the specified datasource in the specified view. You want to use intrinsic functions for these parameters to keep your cross references valid (https://learn.microsoft.com/en-us/dynamicsax-2012/developer/intrinsic-functions).
There will be a lot you can't do though. These are sql only so they cannot send individual rows into X++ business logic. You need to reconstruct said business logic in SQL which can't always be done easily.
I like to keep those methods public so I can info them out and test them in SQL directly. I'm guessing you can't access the sql in d365, but looking at the string returned from your method can still help in troubleshooting.

User Control, Shared Property, setting label text

I usually make user controls containing forms for adding and editing data for a particular table in my database. I then show or hide these controls as the user clicks "edit" buttons, etc. It's common practice (for me) to put properties in the code-behind, that are used for setting the ID of the item being edited, into a hidden label on the page, and of course leaving it blank for new items being inserted. I usually only use C#, however, this time around I have to use VB.NET.
So in C# I would do the following:
public static int EditID
{
get
{
return Convert.ToInt32(lblEditID.Text);
}
set
{
lblEditID.Text = value;
}
}
..and then when the user, say, clicks an "edit" link from a gridview, I would
//set the ID of the corresponding record, something like this:
MyUserControl.EditID = MyGridView.SelectedDataKey[0];
Cool. So now I need to do this in VB.NET, and here's my code:
Public Shared Property EditID As Integer
Get
Return Convert.ToInt32(lblEditID.Text)
End Get
Set(value As Integer)
lblEditID.Text = value
End Set
End Property
but I get a syntax error that says: "Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.", highlighting the lblEditID for both the getter and setter.
I can't find any other SO questions about this, and I have Google'd just about every permutation of keywords I can think of, so this must be something really stupid.
What am I doing wrong here?
EDIT: Yes I realize I could just use a Session variable instead of the label, but I would still like to know why this doesn't work and how I could make it work with a label.
You don't want a Shared property for this. lblEditID is a label that exists in an instance of a WebForm class:- it can't exist until an instance of this class has been created, hence the error.
I don't really understand how the C# worked as this should be the same but I'm not a C# expert.
If you remove the Shared keyword it will work as you want I believe

Overridden function not firing

I've created a control inheriting from gridview:
Partial Public Class nullGridView
Inherits System.Web.UI.WebControls.GridView
Protected Overrides Function CreateAutoGeneratedColumn(ByVal fieldProperties As AutoGeneratedFieldProperties) As AutoGeneratedField
' Create an AutoGeneratedField object.
Dim field As New AutoGeneratedField(fieldProperties.DataField)
' Set the properties of the AutoGeneratedField using
' the values from the AutoGeneratedFieldProperties
' object contained in the fieldProperties parameter.
CType(field, IStateManager).TrackViewState()
field.HeaderText = fieldProperties.Name
field.SortExpression = fieldProperties.Name
field.ReadOnly = fieldProperties.IsReadOnly
field.DataType = fieldProperties.Type
field.NullDisplayText = "NULL"
Return field
End Function
End Class
I can then create instances of the class in codebehind and put them into placeholders. However, the function I'm trying to override never fires. I checked its signature against both Microsoft documentation and other sources, and it appears to be identical to the documented signature, but it never gets invoked. Any suggestions on why it doesn't work, or how to go about debugging this kind of problem?
(Note I also put a constructor into the class, and that got called OK - it is only the above that isn't getting called).
From the GridView.AutoGenerateColumns documentation:
When the AutoGenerateColumns property is set to true, an
AutoGeneratedField object is automatically created for each field in
the data source. Each field is then displayed as a column in the
GridView control in the order that the fields appear in the data
source. This option provides a convenient way to display every field
in the data source; however, you have limited control of how an
automatically generated column field is displayed or behaves.
Are you setting AutoGenerateColumns to true somewhere? You'll also need to give the Grid a data source. What kind of datasource are you using?
If you have set up everything according to the link above, you shouldn't have to override the function to get the behavior in your code because it will automatically create those instances. Further, take a look at the documentation for that function: it's obsolete-- so it's difficult for me to know what it does today.
If you look at the property's documentation it gives some options on how you might control what get's generated, like using a ColumnsGenerator.

Do standard ASP.NET controls connected to an entity datasource provide built in validation?

The entity framework connects to my database to retrieve columns, datatypes, relations, etc. It also knows which columns can be null and not null.
If I connect a regular asp.net grid to an entity datasource, it can generate the grid automatically based on the entity. It knows which fields should be a checkbox based on the datatype, etc.
Since data types are built into the entity class, can a regular asp.net control (like a grid or formview) also perform validation automatically? (or generate the necessary validation controls at least?)
Thanks,
Kevin
Yes, you can display validation errors including validation types using asp:ValidationSummary control. Here one project with this approach used on gridview: http://code.msdn.microsoft.com/ASPNET-Web-Forms-97f8ee9a , check out editing students.
The way to add more validation rules to entities is by attaching meta data.
If you are using EF Code First you can apply rules directly else by adding meta data class, here example:
[MetadataType(typeof(EntityNameMetaData))]
public partial class EntityName {} // name of entity which want to add validation
public class EntityNameMetaData // this is a place, where put validation rules
{
[StringLength(25, ErrorMessage = "First name must be 25 characters or less in length.")]
[Required(ErrorMessage = "First name is required.")]]
//custom or other validation rules
public String EntityProperty
}
this is not possible automatically in asp.net, you would have to define the columns and create item templates to implement this.

Getting the actual field data from a Linq Expression

I'm working on an ASP.NET MVC3 application and I annotated my model with an attribute that specifies what roles can change specific fields for any possible status the model is in. Take this as an example:
public class Model
{
[RoleLimiter(
new[]{Role.Admin, Role.BasicUser, Role.Validator}, // for draft
new[]{Role.Admin, Role.BasicUser, Role.Validator}, // for awaiting validation
new[]{Role.Admin})] // for published etc
public string Subject {get;set;}
}
It looks a bit messy, sure, but it's very easy to change if needed. Now once I have this, it's easy to check for each field the current status and then get the list of roles that can change it. If the current role isn't in it, I'll add a disabled class to the control.
What I wanted to do next is to make a HtmlHelper extension that has the same syntax as the normal EditorFor (or even a straight-forward TextBoxFor), but does this extra check and automatically adds the attribute behind the scenes, but I'm stuck on getting the field info from the expression, ie:
How do you get from
HtmlHelper.TextBoxWithRoleLimitationsFor(x=>x.Subject);
to the attribute attached to x.Subject?
You fetch the LambdaExpression.Body and check whether it's a MemberExpression. You can then get the Member of the MemberExpression and get the custom attributes from that.

Resources