User Control, Shared Property, setting label text - asp.net

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

Related

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.

How to get a public variable (in a Module) to NOT share value between users

I'm working in an ASP.NET (VB) Web Application with Windows/Active Directory Authentication
I am using a module so that I can call public subroutines and functions, and reference variables, without having to instantiate a new object to access them on each page.
Within that module, I have some Public variables that I am using in multiple pages throughout the web application. I've recently realized that the values for these public variables in the module get shared between all users.
THE GOAL:
I want the value for these global variables to be specific to a single user and not shared between all sessions, and I do not want to have to instantiate a new object/class on every page that uses the variable.
THE CATCH:
I don't want to store the value in a client-side variable such as a cookie or session. I want the value to be stored on the SERVER but specific to each client/user.
The only thing I can think to do is setup a global collection/dictionary and store the variables with the authenticated user names, but then I need to have specific functions to get and set the values. While this will work, it requires all the references to these variables on all pages in the application to be updated.
EXAMPLE OF THE PROBLEM:
The below code shows how I am creating the public variable within the module and how the value is being set from one page and used on another. I'd like to continue to use this variable in the same way and share it's value between pages, but the value of the variable needs to NOT be shared between users.
-- MODULE.VB --
Public Module MyMod
Public myVariable as String = ""
End Module
-- MAINPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
myVariable = "HELLO WORLD"
End Sub
End Class
-- NEXTPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
Response.Write(myVariable)
End Sub
End Class
There are a LOT of pages in this application that will need to be manually updated if I have to use my userID-indexed collection solution, so I'm hoping there is a way to simply scope these variables differently or a way to disable the sharing between sessions.
Thanks in advance!
You didn't indicate whether or not the variables need to be persisted across page round trips or whether they are just used within each page's lifecycle.
If they are not persisted across pages, then perhaps the easiest solution is to have all of your pages inherit from a based page class and then move the values from the module into the base page. This way you won't have to change any variable references, only page inheritance.
If you do want to persist the values, completing the above changes makes it much easier to implement. You can then turn the member variables on the base page into properties and embed your user specific caching and fetching in the getter and setter.
For example, instead of:
Public MyVariable As String = ""
You would have something like:
Public Property MyVariable As String
Get
Return GlobalMyVariableCache(UserNameKey)
End Get
Set (Value As String)
GlobalMyVariableCache(UserNameKey) = Value
End Set
End Property
The problem you are coming across is a very common one in web programming. A Module's members are static - meaning there is one instance of them across the entire AppDomain of your application. Every user that accesses these will get the same object - you have already learned this.
Your options are exactly what you described. You could possibly replace the public variable in your module with a property whose getter you write to access a user-specific field in a dictionary (please remember thread safety when writing this getter code).
The much easier solution would be to use the Session. Session values are stored server-side and are user specific. The only thing that get's sent client side is the session key, and if you are using .Net authentication, this is likely already getting sent.
Good luck,

ASP.NET: Can you use server tags to embed C# or VB.NET expressions into a Javascript function?

I have an enum called SiteTypes that contains several values that are all bound to a dropdown list. On the client side, I need to check this dropdown to see if the selected value is one of those enum values. I don't want to hardcode the value of the enum in the script in case it needs to change, so I want to use a server tag to get it directly from the enum itself. Conecptually, I would like to do this:
function SiteIdChanged() {
var x = "<%=SiteTypes.Employee %>";
}
The way I am doing it now is created a protected property in the codebehind that returns that specific enum value and am doing this:
function SiteIdChanged() {
var x = "<%=EmployeeSiteTypeValue %>";
}
I don't like that, though, because I have to create a special property on every page that I need to do such a check.
Is there a way to do what I want here?
Are you getting a "xxx is inaccessible due to its protection level" error when you compile or run the page? enums are public by default, classes are not. My guess is that you've defined your enum inside your page's class and you aren't explicitly marking it with the 'public' access modifier. Explicitly mark it as public or move it outside of the class and see what happens. If you're planning on using it on lots of pages you should stick the enum definition in in a file in the App_Code folder of your project.
If you don't like your current implementation I would consider using a PageMethod to compare the dropdown selection to the enum value. This approach will probably be cleaner, as you can do most of the logic server-side.
Here's a tutorial on PageMethods:
http://blogs.microsoft.co.il/blogs/gilf/archive/2008/10/04/asp-net-ajax-pagemethods.aspx
As long as your enum is marked public, you can just go with your first option. There's no need to put a property on every single page you want to retrieve the value from.
That approach is really the simplest solution for writing out server side values in your JavaScript.
You can use the Enum.IsDefined Method this well tell you if the selected value from the dropdown is actually part of your enum.
Enum.IsDefined(typeof(MyEnum), myValue)
http://msdn.microsoft.com/en-us/library/system.enum.isdefined.aspx

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.

Session Variable Member?

I'm using a compiled .dll provided by someone else -- I know little about it, other than it has a session variable that I must access in a way that is strange to me. Not sure what to call it -- have googled for words that I thought might be right, but so far no success. Here is what it looks like:
Session("receipt").username
It's the .username part that I don't understand. What is it? How is it created?
Thanks for any help.
Session is probably a global object which has a default property which returns a SessionItem object. The SessionItem object is loaded from the browser-session (probably) by the Session object. The SessionItem object has a property username, which is a value stored somewhere in the browser-session.
Some code to clear things up:
Public Class Session
Private Items As SessionItemCollection
Default Public ReadOnly Property SessionItem(ByVal id As String) As Object
Get
Return Me.Items.Find(id)
End Get
End Property
End Class
And you calling the code (Which searches for the "receipt" item in the SessionItemCollection Items from Session):
Session("receipt")
My first guess (since there isn't much other code to go off of) is that the object being stored in the session variable and accessed via Session("receipt") is of a class that contains a property or member called username which you are accessing in that fashion.
The basic idea is that Session("receipt") will pull back whatever this object is (for the sake of instruction we will say it is a receipt object) and the .username is referencing the username property of that receipt object.

Resources