Overridden function not firing - asp.net

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.

Related

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

Extending ASP.NET validators

I want to extend the asp.net validators such that I can make one validator dependent on another. The situation I have is that we have to validate a date in a textbox. Normally I would just use a combination of a RequiredFieldValidator (to ensure the date is provided), CompareValidator (to ensure the date is a date) and finally a RangeValidator (to ensure the date is within the required limit).
The problem with this is that the validators do not depend on each other, so as a result the user would see possibly all three messages at once for each validator when really all we want them to see is the most relevant message, i.e. if they entered "abc" in the date text box it would not be appropriate to show them the message saying the date was not in the valid range (even though technically I suppose this is true).
Currently to provide this kind of functionality we use a CustomValidator and just put all three validations within the server validate event handler and change the error message programmatically depending on what validation failed.
I would like to standardize this a bit more as it happens quite a bit in this application, I figure if I can make the validators dependent on each other this will solve the problem and also allow us to make use of the client side validation rather than having to do a postback especially to handle the custom validation.
The idea is that if one validator is dependent on another if that "master" is valid then the depended will perform its normal validation (EvaluateIsValid()) otherwise if the master validator is not valid then the other dependent validators will be valid.
I have come up with the following solution by inheriting from the various validator controls that already have been provided in the framework.
public class RequiredFieldDependentValidator : RequiredFieldValidator
{
[Description("The validation control to depend on for determining if validation should occur")]
public string ValidationControlToDependOn
{
get
{
object obj = ViewState["ValidationControlToDependOn"];
if (obj != null) return (string) obj;
return null;
}
set
{
Control control = FindControl(value);
if (control is IValidator)
ViewState["ValidationControlToDependOn"] = value;
else
throw new HttpException("ValidationControlToDependOn is not a validation control");
}
}
protected override bool EvaluateIsValid()
{
IValidator validationControlToDependOn = FindControl(ValidationControlToDependOn) as IValidator;
if(validationControlToDependOn != null)
{
return !validationControlToDependOn.IsValid || base.EvaluateIsValid();
}
return base.EvaluateIsValid();
}
Currently I have just coded it for the RequiredFieldValidator, ideally I would like to provide this functionality for all of the validators but I cannot see a way to do this without copying the above code into a similar class for each individual type of validator I want to provide this functionality for thus if there are any problems I'm going to have to go back and change this code on each validator type individually.
Is there a way I can "centralise" this code and have it easily used in the validators without having to write the entire validators from scratch just so I can change the class they inherit from further down the line.
Cheers,
You could override the Validate method in you page base. To add the validation dependency information in the page you can implement a not rendered control:
<my:ValidationDependency TargetControl="RegExp1" Dependency="Required1" />
You might want to look into a WebControlAdapter.
Basically allows you to override certain methods of webcontrols (conditionally for some browsers if need, but here can be for all).
In your case, you would want to override the EvaluateIsValid method and check if the control has any dependency on a 'parent' validator.
As an example, a TextBox adapter we recently created to render a 'maxlength' attribute to the control.
Public Class TextBoxAdapter
Inherits WebControlAdapter
Private ReadOnly Property TextBoxControl() As TextBox
Get
Return DirectCast(MyBase.Control, TextBox)
End Get
End Property
Protected Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter)
If TextBoxControl.TextMode = TextBoxMode.MultiLine AndAlso TextBoxControl.MaxLength > 0 Then
writer.AddAttribute("maxlength", TextBoxControl.MaxLength.ToString)
End If
MyBase.RenderBeginTag(writer)
End Sub
End Class
To use it, just create a .browser file in your App_Browsers directory and setup the adapter there:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.TextBox"
adapterType="TextBoxAdapter" />
</controlAdapters>
</browser>
</browsers>
The only complication that still remains in your case is how to store the dependent validator in order for the EvaluateIsValid to have access to this directory. You might consider a non-rendered control like Onof suggested or else Viewstate/Cookie/other storage mechanism.
you can have ValidationControlToDependOn property as of type List and add the validators into the list. So we can assume that the validator added later depends upon the validator added before it.
so your protected override bool EvaluateIsValid()
will change somewhat
foreach(IValidator validator in ValidationControlToDependOn)
{
return !validator.IsValid;
}
I'm looking into control extenders which seems like it could be promising but I cannot find many examples of doing anything but AJAX stuff with it.

Can you prevent LinqDataSource from setting a property?

I've got a Linq 2 SQL object I'm trying to update. Two of the properties on this object are related to each other, and setting one sets the other.
So if I do:
Foo.Code = BEER;
The Foo.CodeID property will automatically be set to 5 (or whatever.)
The problem is that LinqDataSource sets Foo.Code, then immediately sets Foo.CodeID... which is not bound to anything since we want the users to set just Code. This immediately sets them both back to null.
I know I can use Parameters to default values, but is there any way to just tell LinqDataSource to not even set a property?
EDIT: Worked around issue by creating a hidden field, and assigning the correct value to that in the formview's ItemUpdating event. Would still like to avoid doing the same lookup four times though...
Would it be an option to make the Code property private (select the Code property in the dbml and set the access property in the Properties window) and create a new public property over which you have more control?
I personally have have written a generator that generates the necessary files for me (like sqlmetal), giving me full control over the code. Perhaps this is an option for you as well, if you do not like the generated dbml.

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

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

How do I set up ObjectDataSource select parameters at runtime

I'm trying to add parameters to an objectDataSource at runtime like this:
Parameter objCustomerParameter = new Parameter("CustomerID", DbType.String, customerID);
Parameter objGPDatabaseParameter = new Parameter("Database", DbType.String, gpDatabase);
//set up object data source parameters
objCustomer.SelectParameters["CustomerID"] = objCustomerParameter;
objCustomer.SelectParameters["Database"] = objGPDatabaseParameter;
At what point in the objectDataSource lifecycle should these parameters be added (what event)? Also, some values are coming from a master page property (which loads after the page_load of the page containing the objectDataSource).
Add them to the event for the operation you are trying to use. For example, if these parameters are part of the SELECT command then add them to the Selecting event, if they need to go with the UPDATE command then add them on the Updating event.
The ObjectDataSource raises an event before it performs each operation, that's when you can insert parameters (or validate/alter existing parameters).
Also, don't try and modify the parameters collection of the ODS itself. You want to add your parameters to the ObjectDataSourceSelectingEventArgs that is passed to the event handler.
Something like:
e.InputParameters["CustomerID"] = customerId;
e.InputParameters["database"] = dbName;
Add as early as possible; at the PreInit event. This is part of initialization so should be done there.
See the ASP.NET Page Life Cycle Overview for more information.

Resources