form view and external IBindableTemplate - c#

I would like to set the one template for edit/insert and view in my custom FormView control . But i got these odd exception
Unable to cast object of type 'System.Web.UI.LiteralControl' to type 'System.Web.UI.WebControls.Table'.
public class CustomFormView : FormView
{
[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(FormView), BindingDirection.TwoWay)]
public IBindableTemplate FormTemplate { get; set; }
protected override void OnInit(EventArgs e)
{
ChangeMode(FormViewMode.Edit);
if (FormTemplate != null)
{
if (CurrentMode == FormViewMode.Edit)
{
FormTemplate.InstantiateIn(this);
}
}
base.OnInit(e);
}
}
edited :
in the first step , I created the new user control and added a formview ("FV")
public partial class Form : UserControl
{
private IBindableTemplate _template = null;
[PersistenceMode(PersistenceMode.InnerProperty),
TemplateContainer(typeof(FormView), System.ComponentModel.BindingDirection.TwoWay)]
public IBindableTemplate FormTemplate { set;get }
protected void Page_Init()
{
if (FormTemplate != null)
{
FV.InsertItemTemplate = FV.EditItemTemplate = FormTemplate;
if (!IsPostBack) FormTemplate.InstantiateIn(FV);
}
}
}
Now , I want to convert this user control to web control .
I would appreciate it if you could reply my question.

What exactly are you trying to do??
Whatever it is you're trying to do, you're doing it wrong.
TemplateContainer(typeof(FormView)) This is not possible.
You need to provide your own type there, inheriting from IDataItemContainer.
Edit:
I wouldn't recommend putting all this effort just because you want to have 1 template for edit and insert. Better put the same contents in both templates. Experience learns that over time you will want distinct functionallity for edit and insert.

Related

Im getting "an object reference is required for the non-static field" exception on non static methods... what am I doing wrong?

I have a default page and an analisis page, and at Default I have some radio buttons to change a table, but I'm getting a "an object reference is required for the non-static field" exception on compilation, everything is non-static, and I haven't figured out why I'm getting this error.
Here's the code for _Default:
public partial class _Default : System.Web.UI.Page {
public bool Carro {
get { return radCarroSi.Checked ;}
}
}
And here is the code for Analisis:
public partial class Analisis : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
_Default prevPage = PreviousPage as _Default;
if (prevPage != null) {
if (_Default.Carro == true) {
row8.Visible = false;
}
}
}
}
}
Can you help me? I believe its pretty easy but as I'm new at asp I haven't seen the problem.
Thanks in advance.
You don't have an instance of _Default:
You're just referring to the class name, not the instance of the class.
To elaborate a little further.
public class YourClass
{
public bool Carro { get; set; }
}
YourClass instance = new YourClass(); // this would create a new instance of `YourClass`.
You can refer to it by using instance.Carro like you have done with _Default.Carro
However I believe you are trying to determine if the value of Carro has been checked in the page, ASP.NET doesn't work quite like this, you will need to understand how to manage state between the client and server. This can be achieved via ViewState, Session, Cookies and Query Strings
You can't check if a radio button is checked in a different page so this line will not work in the Analisis page (besides, you don't even have an instance of _Default):
if (_Default.Carro == true) {
row8.Visible = false;
}
You need to pass the radion button value between pages using Session, Querystring or some other method

ASP.NET expose controls to other class

I have been battling this for some time and I need some guidance.
I'm coding in ASP.NET 4.0 WEBFORMS.
Question is: How to expose a textbox, Label or any other control to another class.
I have a webform (see below).
public partial class WebForm1 : System.Web.UI.Page
{
}
This is then referenced and sent to another class.
public class SearchInitializer
{
private WebForm1 _webform1;
public SearchInitializer(WebForm1 Webform1)
{
_webform1 = Webform1;
}
public void ChewSettings()
{
_webform1 //can't find any control in here?!
}
}
First I thought of creating a public property which I thought I could access from the reference I sent to the new class.. But nooo!
public partial class WebForm1 : System.Web.UI.Page
{
public string KeywordBox1
{
get {return txt_keyword.Text;}
set {txt_keyword.Text = value;}
}
}
The I tried to inherit the Webform into the other class. Making the the property available but no luck there.
public class SearchInitializer : Webform1
{
private WebForm1 _webform1;
public SearchInitializer(WebForm1 Webform1)
{
_webform1 = Webform1;
}
public void ChewSettings()
{
_webform1 //can't find any control in here?!
}
}
Okay an abstract class migth be of use here, inheriting everything. But I think I got that wrong to. I have events and static classes, so they can talk with the page. But I really would like not to use a static class as a container to save all the info in my controls.
So these are the examples I have tried and they all failed. So this is me basicly trying to expand what I know ;) Thanks for reading!!
Why have they failed and how should I do it?
EDIT AS REQUESTED!
public partial class WebForm1 : System.Web.UI.Page
{
protected void btn_click(object sender, EventArgs e)
{
SearchInitializer searchIni = new SearchInitializer(this);
}
}
To expose the controls there are two methods I can think of that you can employ.
You can remove the following statement from the myPage.designer.cs file and place it in your code behind as a public declaration:
protected global::System.Web.UI.WebControls.TextBox myTextBox;
becomes
public System.Web.UI.WebControls.TextBox myTextBox;
This should make it immediately accessible. My preferred method is to add a property for each specific control that you want to provide access to.
public System.Web.UI.WebControls.TextBox MyTextBoxElement
{
get
{
return myTextBox;
}
}
This allows to provide supplementary access controls if you need them or other conditionals. In any case, to access either the field or the property, the consuming object must reference this by your specific page type.
Not sure what you are trying to do, but to access a base class within an inherited calss you need to use the base keyword, not declare an instance there of.
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public string KeywordBox1
{
get { return txt_keyword.Text; }
set { txt_keyword.Text = value; }
}
}
public class SearchInitializer : WebForm1
{
public SearchInitializer()
{
}
public void ChewSettings()
{
// Works
base.KeywordBox1 = "Red";
}
}
If intellisense is not showing the property, try rebuilding the solution. It will then refresh the list of available properties and it should show.
Your original approach must work. I suggest you create a small test project with a form with text box and SearchInitializer class and see that it works, after that figure out what is different in your current project.

passing values between composite controls

I have a control : composite control that defines a button. The button calls a Command event and sets the value of another control's property, before making the control visible.
Both of these controls are instantiated within a container control before hand. I need to grab the value of the property in the second form within the CreateChildControls() method, however, this is not possible, why?
Scenario:
public class Main : CompositeControl
{
#region fields
private StepPersonal _stepPersonal;
private StepFinancial _stepFinancial;
#endregion
protected override CreateChildControls()
{
this._stepPersonal = new StepPersonal { ID = "StepPersonal1", Visible = true };
this.Controls.Add(this._stepPersonal);
this._stepFinancial = new StepFinancial { ID = "StepFinancial1", Visible = false };
this.Controls.Add(this._stepFinancial);
}
protected override Render(HtmlTextWriter writer)
{
this._stepPersonal.RenderControl(writer);
this._stepFinancial.RenderControl(writer);
}
}
StepPersonal:
public class StepPersonal : CompositeControl
{
#region fields
private Button _checkDetails;
#endregion
protected override CreateChildControls()
{
this._checkDetails = new Button { ID = "CheckDetailsButton", Text = "CheckDetails", CommandName = "DetailsConfirmation" }
this._checkDetails.Command += new CommandEventHandler(this.OnCheckDetails);
this.Controls.Add(this._checkDetails);
}
protected override Render(HtmlTextWriter writer)
{
this._checkDetail.RenderControl(writer);
}
protected void OnCheckDetails(object sender, CommandEventArgs args)
{
string argument = args.CommandArgs.ToString();
this.Visible = false;
Main owner = (sender as Button).FindParent<Main>(); // custom extension method
StepFinancial sf = owner.FindControl<StepFinancial>("StepFinancial1");
sf.Argument = argument;
sf.Visible = false;
}
}
Then lastly, and this is where my problem lies, the StepFinancial control
public class StepFinancial : CompositeControl
{
#region fields
private TextBox _argumentTextBox;
#endregion
#region properties
public string Argument { get; set; }
#endregion
protected override CreateChildControls()
{
string argument = this.Argument; // this is always null
// I have buttons in here (not being displayed) who's events are not wiring up
// if I move this into a method, and call the method in Render(), as it seems
// to allow me access to the properties there, but I need the value here?
}
protected override Render(HtmlTextWriter writer)
{
string argument = this.Argument; // this contains the value of the property set previously
this._argumentTextBox.RenderControl(writer);
}
}
I've tried adding the value to a StateBag, nothing. I tried adding a QueryString in the CommandEventHanlder, but get a collection is locked error message. I tried cache and Sessions (sessions won't work cause this will be deployed to SharePoint) so that's out of the question. I've tried Googling, Bing'ing even Yahoo! this but no luck.
Update
I failed to mention, I can't add the controls to the collection under OnPreRender as it does not wire up any of the events. I can't use EnsureChildControls either as it screws up other parts of the application. I can, however, add the value from the property at this level, to a statebag, but I feel this is a very bad way of doing it.
I did not really resolve this in a matter that I would feel comfortable with, but I have a NoSQL solution underlying this, and store the values between the controls in there and dispose of it when the application closes.

How best to deal with dynamic page settings in a C# ASP.NET web application?

I have a single page that has a number of controls configured a certain way depending on some condition (e.g. if it is a user accessing the page or an admin). How I currently achieve this is by having an interface for the settings which are common to all pages, and then extending classes which implement the properties specific to the type of user.
For example:
public interface Display_Type
{
string backgroundColor { get; }
}
public class AdminPage : Display_Type
{
string backgroundColor { get { return "orange"; } }
}
public class UserPage : Display_Type
{
string backgroundColor { get { return "blue"; } }
}
And my page's codebehind:
public partial class MyPage : System.Web.UI.Page
{
Display_Type pageSettings;
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
pageSettings = new AdminPage();
}
else
{
pageSettings = new UserPage();
}
// ...
string backgroundColor = pageSettings.backgroundColor;
// ... Do stuff with background color
}
}
This works fine for me, but since these settings are constant across the application, they seem to make more sense as static classes. However, I'm having trouble figuring out how to do this because I can't assign a static class to a variable.
My questions are:
Is there a better way I can accomplish what I'm trying to do here?
Or, if this is okay, how could I accomplish what I'm doing with static classes / members?
It may be worth noting that the user/admin example is not how I'm using this structure in my web application, and in fact has nothing to do with the user themselves but rather other factors such as request parameters.
Put your settings on the BasePage and have other pages derive from it.
You will set the settings only once.
public abstract class MyBasePage : System.Web.UI.Page
{
protected Display_Type PageSettings { get; private set; };
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
PageSettings = new AdminPage();
}
else
{
PageSettings = new UserPage();
}
}
}
public partial class MyPage : MyBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
// ...
string backgroundColor = PageSettings.backgroundColor;
// ... Do stuff with background color
}
}
This is not how I would do this, but if you are doing it this way, static classes have absolutely nothing to do with and no use in this situation.
You might consider having a single instance of each of the Display_Type classes stored somewhere to be reused, instead of creating a new one each time, though. This might end up being as a static variable... but that's not the same at all as a static class.
You can use a singleton to define your AdminPage and UserPage profile and add a static method GetDisplayType() to your implementation.
public static class PageTypes {
public static PageType Admin(/** stuff here */);
public static PageType User(/** stuff here */);
}
public class PageType {
readonly string _backgroundColor;
public PageType (/** stuff here */) {
_backgroundColor = backgroundColor;
}
public string BackgroundColor {
get {
return _backgroundColor;
}
}
So now, you can access them like this in your method:
if ((bool)Session["Is_Admin"])
{
PageSettings = PageTypes.Admin;
}
else
{
PageSettings = PageTypes.User;
}
I agree with Jakub about using the base class to prevent code duplication.
1. Is there a better way I can accomplish what I'm trying to do here?
Microsoft .NET has a built-in application settings implementation: setting files. Just use them if your settings aren't configurable by each user.
Application settings can be defined in a satellite assembly and overridden in the app.config or web.config of your application.
That's I find better to define such settings using setting files, which is a built-in, understandable and well-implemented solution and you've it out-of-the-box.
How to accomplish your goal using setting files?
You can use configuration by convention, and your background color settings will look like this:
AdminPage_BackgroundColor => #000000
UserPage_BackgroundColor => #FFFFFF
and so on
In your case, you've two background color settings for both pages, but if you'd need to configure background color for any of pages, you'd do this in your Page-derived class instance:
Properties.PagesStyle.Default[GetType().Name + '_' + "BackgroundColor"]
And you'll be able to get background color by page and from your settings file.
Let's implement this in your page class:
public partial class MyPage : System.Web.UI.Page
{
Color backgroundColor = null;
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
backgroundColor = Properties.PagesStyle.Default.AdminPage_BackgroundColor;
}
else
{
backgroundColor = Properties.PagesStyle.Default.UserPage_BackgroundColor;
}
// ... Do stuff with background color
}
}
Note settings files allow you to define strongly-typed values. Let's say you typed "UserPage_BackgroundColor" as System.Drawing.Color, designer will edit color by using a color picker, and when you access to this setting, you'll get a System.Color instead.
Before begin with another approach, check these useful links:
Settings files in MSDN: http://msdn.microsoft.com/en-us/library/aa730869(v=vs.80).aspx
Some other answer I did some time ago: Can a class library have an App.config file?
Recommended approach
There's a solid, stable and valuable way of styling Web sites: CSS.
Instead of creating your own styling approach, just play with CSS classes.
For example, in some CSS stylesheet you define both background colors for admin page and user page:
body.UserPage
{
background-color: #000;
}
body.AdminPage
{
background-color: #FFF;
}
Just imagine you've this ASP.NET page (I'll include standard XHTML markup only):
<html>
<head></head>
<body id="body" runat="server"></body>
</html>
In your code-behind code perhaps you can do this:
public partial class MyPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
body.Attributes["class"] = "AdminPage";
}
else
{
body.Attributes["class"] = "UserPage";
}
}
}
This way you avoid:
Creating redundant settings since you use CSS as styling mechanism (don't reinvent the wheel!).
Compiling styling values: it's a client-side thing, because it's CSS.
To answer your second question, a implementation of a static solution:
public interface IDisplayType
{
string backgroundColor { get; }
}
public class AdminPage : IDisplayType
{
public string backgroundColor { get { return "orange"; } }
}
public class UserPage : IDisplayType
{
public string backgroundColor { get { return "blue"; } }
}
public static class PageProperties
{
private static AdminPage _adminPage = new AdminPage();
private static UserPage _userPage = new UserPage();
public static IDisplayType DisplayType { get
{
if ((bool)HttpContext.Current.Session["Is_Admin"])
{
return _adminPage;
}
return _userPage;
}
}
I also changed the type Display_Type to IDisplayType which gives a beter description of what it is.
You could then use the following code in your page.
string backgroundColor = PageProperties.DisplayType.backgroundColor;

Visual Studio uses UserControlDesigner instead of CustomDesigner

I've got an ASP-UserControl QuestionWithAnswer (.ascx) : BaseQuestion : UserControl
and a ControlDesigner QuestionDesigner : UserControlDesigner.
Now i use the DesignerAttribute to associate control and designer:
[Designer(typeof(QuestionDesigner))]
public class BaseQuestion : UserControl
all types are in the same assembly (WEB Application).
But it still loads UserControlDesigner instead of mine.
Did i have to put my designer in a seperate assembly?
I suppose the asp-page designer cannot find the designer.
thx!
mo
demo code:
public class FragenDesigner : UserControlDesigner
{
private DesignerActionList _actionList;
private DesignerVerb[] _verbs;
public override DesignerActionListCollection ActionLists
{
get
{
if (_actionList == null)
{
_actionList = new DesignerActionList(new System.Windows.Forms.TextBox());
_actionList.AutoShow = true;
ActionLists.Add(_actionList);
}
return base.ActionLists;
}
}
public override DesignerVerbCollection Verbs
{
get
{
if (_verbs == null)
{
_verbs = new DesignerVerb[]
{
new DesignerVerb("test", onblabla),
};
Verbs.AddRange(_verbs);
}
return base.Verbs;
}
}
private void onblabla(object sender, EventArgs e)
{
MessageBox.Show("blabla");
}
}
okay there is already an answer: http://msdn.microsoft.com/en-us/library/system.web.ui.design.usercontroldesigner.aspx.
Remarks
There is no developer advantage to
creating your own designer derived
from UserControlDesigner. To enhance
the design-time experience for a
custom control, derive your control
from CompositeControl and your
designer from
CompositeControlDesigner. In that
case, you would not use an .ascx file
for your ASP.NET markup.
In my case there is no possibility to change to CompositeControls.
Trust me, i prefer Composite/WebControls ...

Categories