|
Subject:
|
Why would anyone use MS Widgets?
|
|
Posted By:
|
David_0223
|
Post Date:
|
5/17/2008 10:44:23 PM
|
Sorry, this is just a rant. Every time I try to use one of those nifty widgets Microsoft gives us that are supposed to reduce the amount of code you write (something I love doing), I wind up spending many hours trying to get the widget to do what I want it to.
I'm fairly new to ASP.Net so I thought I'd try some of the Data controls. The FormView looks particularly useful so ... I've spent several hours now trying to get it to work. The multiple templates looks cool, but I can't get it swap to the template I want. Apparently you can't access the events of the controls inside a FormView ... :-(
According to MS's documentation the wizard creates buttons for each template that could be used to change the current mode (template), but it's not clear how to make them work. So I'll go back to writing code, with which I can always get the result I want, and hope that some day Microsoft makes some usable widgets.
What you don't know can hurt you!
|
|
Reply By:
|
samjudson
|
Reply Date:
|
5/18/2008 3:57:01 AM
|
Hi
I'm not sure what the 'widget' you are refering to is, so can't really help. Do you mean an ASP.Net web control? Is it one of the built in ones? If you could try and explain which control you are using and provide code examples then maybe we could help.
Sam
/- Sam Judson : Wrox Technical Editor -/
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/19/2008 10:29:03 AM
|
Hi Sam,
I'll take the DropDownList (DDL) widget for example. This seems like an extremely valuable tool to anyone who has ever coded one in html using javascript and asp. The problem is in getting it to work. I have an example I added to a project, the purpose (of the DDL) is to change the data displayed on the page based on the users selection on the DDL.
I bound the DDL to a SqlDataSource and that populated the list with no problem. I set "AutoPostBack" to true and set up an event handler for the "TextChanged" event in the Page_Load method. Now we begin to see things fall apart. While changing the selected item does post back to the web site, the "TextChanged" handler method I setup does not get called! Bummer! But the Page_Load gets called and IsPostBack is true so maybe we can use this to process our change. So I look (using the IDE's watch) at the sender object where I can see my DDL and it doesn't even have the list populated, much less what my selection was.
So, in the end, the MS widget DropDownList is, more or less, worthless. Ahh but you say it saved me from having to write all that code to populate the options in my html select statment! True, but I can't use it to effect a change in the webpage...
I find this is generally true of all Microsoft widgets. They only work in a very limited sense. As soon as you want some custom behavior, you need to code the whole thing. That's my gripe!!
What you don't know can hurt you!
|
|
Reply By:
|
samjudson
|
Reply Date:
|
5/19/2008 10:39:57 AM
|
I think you might have been more interested in the SelectedIndexChanged event, rather than the TextChanged.
An no-one calls them widgets, so it would help your understanding (and others) if you called them Web Controls.
I'll be honest, DropDownList is one of the built in web controls, so if you are finding it useless then it is more likely to be because you are misunderstanding something rather than it actually being useless.
/- Sam Judson : Wrox Technical Editor -/
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/19/2008 11:07:10 AM
|
Sam,
Don't get me wrong, I'm not saying Microsoft doesn't do anything of value, I just wish some of their more exotic controls worked in more situations.
By the way the "SelectedIndexChanged" works the same as the "TextChanged" event does ... it doesn't fire at all! Now there may be someway you can tell that it fired but you can't set up an event handler in the code that generated the page and expect to capture the event as you could if this were a DropDownList on a Window's Form.
As for widgets, I may be old enough to be your father so that term may pre-date you by a bit. It's not a technical term but a generic term that has to be understood within the context of it's use.
What you don't know can hurt you!
|
|
Reply By:
|
Imar
|
Reply Date:
|
5/19/2008 12:09:30 PM
|
Of course the SelectedIndexChanged fires and in a pretty similar way to what you'd see in a Win Forms application. Consider this example:<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
string[] movies = new string[] { "Reservoir Dogs", "Pulp Fiction", "Killing Zoe" };
DropDownList1.DataSource = movies;
DropDownList1.DataBind();
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label1.Text = string.Format("You selected {0}", DropDownList1.SelectedValue);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="DropDownList1" runat="server"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"
AutoPostBack="true">
</asp:DropDownList>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</div>
</form>
</body>
</html>What do you think will happen? Will the label get the right value of the movie you choose?
Nope, it doesn't. Page_Load *always* fires, both on initial load and on PostBack and does so *before* other events like SelecedIndexChanged and Click of a button fires. What happens when you choose a new item in the list? The list is *repopulated* with the movies, overwriting your selection and resetting things to how they were the first time. Clean list + no selection == no SelectedIndexChanged. Quite likely the behavior you are witnessing.
What's the fix? Don't load the data on PostBack:<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string[] movies = new string[] { "Reservoir Dogs", "Pulp Fiction", "Killing Zoe" };
DropDownList1.DataSource = movies;
DropDownList1.DataBind();
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label1.Text = string.Format("You selected {0}", DropDownList1.SelectedValue);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="DropDownList1" runat="server"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"
AutoPostBack="true">
</asp:DropDownList>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</div>
</form>
</body>
</html>With this code, everything works as expected.
Note that although this is a simple example, the principle applies to many other controls and situations. The fact things don't work as you expect may not have to do with the actual controls, but may have to do with your knowledge and the way you use these controls.
So, instead of complaining about dysfunctional widgets, I think you're better off trying to find out *why* things don't work, widen your knowledge and then fix your code so it does what you want, using the tools that are meant to be used.
BTW: you *can* get events in controls to fire, and you *can* switch templates. However, instead of calling method like ChangeMode, you need to set the DefaultMode property to a value from the FormViewMode enumeration: Insert, Edit or ReadOnly.
Cheers,
Imar
--------------------------------------- Imar Spaanjaars http://Imar.Spaanjaars.Com Everyone is unique, except for me. Author of Beginning ASP.NET 3.5 : in C# and VB, ASP.NET 2.0 Instant Results and Dreamweaver MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/19/2008 1:04:14 PM
|
Imar,
The difference between what you did and what I did was in the declaration statement:
<acp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
</acp:DropDownList>
I was registering the event handler in Page_Load ...
protected void Page_Load(object sender, EventArgs e) {
if(!Page.IsPostBack)
{
DropDownList1.OnSelectedIndexChanged +=
new EventHandler(DropDownList1_SelectedIndexChanged);
}
}
Obviously, this didn't work.
I prefer to find out why things work and why they don't work, but it can be challenging to find this information.
Thanks for the enlightenment!
What you don't know can hurt you!
|
|
Reply By:
|
Imar
|
Reply Date:
|
5/19/2008 1:13:25 PM
|
Hi David,
It *does* work, provided you use the right code.
First of all, you need to use DropDownList1.SelectedIndexChanged rather than DropDownList1.OnSelectedIndexChanged, but maybe that's just a typo in this post.
Secondly, because event handlers are not persisted in ViewState, you need to set up the handler on initial load and PostBack as well. The following example has programmatic wiring of the event handlers and has the exact same behavior as my previous example:<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string[] movies = new string[] { "Reservoir Dogs", "Pulp Fiction", "Killing Zoe" };
DropDownList1.DataSource = movies;
DropDownList1.DataBind();
}
DropDownList1.SelectedIndexChanged += new EventHandler(DropDownList1_SelectedIndexChanged);
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label1.Text = string.Format("You selected {0}", DropDownList1.SelectedValue);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="DropDownList1" runat="server"
AutoPostBack="true">
</asp:DropDownList>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</div>
</form>
</body>
</html>Cheers,
Imar
--------------------------------------- Imar Spaanjaars http://Imar.Spaanjaars.Com Everyone is unique, except for me. Author of Beginning ASP.NET 3.5 : in C# and VB, ASP.NET 2.0 Instant Results and Dreamweaver MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/19/2008 2:53:21 PM
|
Imar,
AS you alluded to I typed that code before rather than copy and paste it from my code. When I have registered the event handler in Page_Load I used the IDE code template and it completed the registration and generated the stub method. I typically use code in a separate file. So here is some code from my project:
From CEMDevMgmnt.ascx:
<asp:TableCell ID="DeviceList" >
<asp:DropDownList ID="cboDevices" runat="server" OnSelectedIndexChanged="cboDevices_Selected" AutoPostBack="true">
</asp:DropDownList>
</asp:TableCell>
and from CEMDevMgmnt.ascx.cs:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
this.cboDevices.DataSource = this.SqlAlalyzerList;
this.cboDevices.DataTextField = "ANALYZER_NAME";
this.cboDevices.DataBind();
}
}
protected void cboDevices_Selected(object sender, EventArgs e)
{
GetData(cboDevices.SelectedValue);
}
"GetData()" takes a device name as an argument, queries the database and populates the rest of the values on the form. Except cboDevices_Selected never gets called!
What you don't know can hurt you!
|
|
Reply By:
|
Imar
|
Reply Date:
|
5/19/2008 3:08:00 PM
|
quote: I typically use code in a separate file.
Me too. I posted the example with in-line code as it's easier to communicate over a forum post.
Anyway, it shouldn't be like this. I have pretty similar code and it works fine:
[Default.aspx] <form id="form1" runat="server"> <div> <asp:DropDownList ID="cboDevices" runat="server" AutoPostBack="True" onselectedindexchanged="cboDevices_SelectedIndexChanged"> </asp:DropDownList> </div> </form>
[Default.aspx.cs] protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { string[] movies = new string[] { "Reservoir Dogs", "Pulp Fiction", "Killing Zoe" };
this.cboDevices.DataSource = movies; this.cboDevices.DataBind(); } } protected void cboDevices_SelectedIndexChanged(object sender, EventArgs e) {
}
cboDevices_SelectedIndexChanged gets hit every time.
I noticed you use event wiring in the control's markup, not programmatially as you said earlier. Which of the two techniques are you using?
Maybe you're not showing us the whole picture? Maybe something else is messing with your page and/or DropDownList?
Imar
--------------------------------------- Imar Spaanjaars http://Imar.Spaanjaars.Com Everyone is unique, except for me. Author of Beginning ASP.NET 3.5 : in C# and VB, ASP.NET 2.0 Instant Results and Dreamweaver MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/19/2008 4:08:24 PM
|
Actually, I will use any technique I can get to work. Here's a piece that may relavent. The project itself uses one main web page divided up with tables. There's an area for the header, footer and a menu area. Then there is a cell for the Data. Each group of data that I need to present is contained in a user control. Depending on the menu selection I load the web page with the appropriate control. This particular control is the Device Manager which is responsible for determining which devices will be monitored. I call the user control with:
else if (this.Request.QueryString["datapage"] == "devadmin")
{
try
{
DevMgr.Roles = Roles;
this.PageData.Controls.Clear();
this.PageData.Controls.Add(DevMgr);
DevMgr.Visible = true;
}
catch (Exception ex)
{
WriteLog(ex.Message);
}
}
Every user control has to exist and be registered in the main web page. That's why you see the line "DevMgr.Visible = true;"
Where this is particularly noticible is when a Post occurs it goes to the default.aspx not to CEMDevMgmnt.aspx where the actual dropdownlist is located and where the code for it is contained.
Do you think that makes a difference. Because some of the code works as expected. Page_Load in the user control, for instance, is always called when a Post occurs. And I have 4 buttons in the last row of the table that all work now that I have put the OnClick registration in the declaration portion.
What you don't know can hurt you!
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/19/2008 5:47:32 PM
|
One more shot at it. I created a new user control. This one is for managing user access to the system. It still needs a lot of work, but to keep it short I just basically created it with the wizards. Added 3 SQLDataSources for 2 list boxes and a dropdown listbox. One listbox shows the available access roles, the other shows the roles assigned to the user which is in the dropdownlist. When you select a different user in the dropdownlist, that users access should appear... it doesn't. here's the code:
.aspx code:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="CEMUserMgmnt.ascx.cs" Inherits="pages_CEMUserMgmnt" %>
<asp:SqlDataSource ID="CEMSqlGroups" runat="server" ConnectionString="<%$ ConnectionStrings:TOL_CEM_Connect %>"
SelectCommand="SELECT [Group_Name] FROM [Access_Groups]"></asp:SqlDataSource>
<asp:SqlDataSource ID="CEMSqlUserGroups" runat="server" ConnectionString="<%$ ConnectionStrings:TOL_CEM_Connect %>"
SelectCommand="cemGetUserRoles" SelectCommandType="StoredProcedure">
<SelectParameters>
<asp:ControlParameter ControlID="cboUsers" Name="username" PropertyName="SelectedValue"
Type="String" />
</SelectParameters>
</asp:SqlDataSource>
<asp:SqlDataSource ID="CEMSqlUsers" runat="server" ConnectionString="<%$ ConnectionStrings:TOL_CEM_Connect %>"
SelectCommand="SELECT [User_Name] FROM [Users]"></asp:SqlDataSource>
<table style="width: 641px; height: 122px">
<tr>
<td>
Users</td>
<td style="width: 154px">
User Groups</td>
<td style="width: 38px">
</td>
<td>
Available Groups</td>
</tr>
<tr>
<td>
<asp:DropDownList ID="cboUsers" runat="server" AutoPostBack="True"
DataSourceID="CEMSqlUsers" DataTextField="User_Name" DataValueField="User_Name" OnSelectedIndexChanged="cboUsers_SelectedIndexChanged">
</asp:DropDownList></td>
<td style="width: 154px">
<asp:ListBox ID="ListBox1" runat="server" DataSourceID="CEMSqlUserGroups" DataTextField="Group_Name"
DataValueField="Group_Name"></asp:ListBox></td>
<td style="width: 38px">
<table style="width: 35px">
<tr>
<td>
<asp:Button ID="btnAddAll" runat="server" Text="<<" /></td>
</tr>
<tr>
<td>
<asp:Button ID="btnAddOne" runat="server" Text=" < " /></td>
</tr>
<tr>
<td>
<asp:Button ID="btnRemOne" runat="server" Text=" > " /></td>
</tr>
<tr>
<td style="height: 20px">
<asp:Button ID="btnRemAll" runat="server" Text=">>" /></td>
</tr>
</table>
</td>
<td>
<asp:ListBox ID="lstAccessGroups" runat="server" DataSourceID="CEMSqlGroups" DataTextField="Group_Name"
DataValueField="Group_Name"></asp:ListBox></td>
</tr>
<tr>
<td>
<asp:Button ID="btnCancel" runat="server" Text="Cancel" />
</td>
<td style="width: 154px">
</td>
<td style="width: 38px">
</td>
<td>
<asp:Button ID="btnSave" runat="server" Text="Save" /></td>
</tr>
</table>
and Here is the .aspx.cs code:
using System;
using System.Data;
using System.IO;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class pages_CEMUserMgmnt : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void WriteLog(string Msg)
{
try
{
StreamWriter err_log = File.AppendText(this.Request.Params["APPL_PHYSICAL_PATH"] +
"\\logs\\error.log"); if (err_log != null)
{
err_log.WriteLine("{0}::{1}::{2}", DateTime.Now, this.ClientID, Msg);
err_log.Close();
}
}
catch (Exception)
{
}
}
protected void cboUsers_SelectedIndexChanged(object sender, EventArgs e)
{
WriteLog(String.Format("Selected user {0}.", cboUsers.SelectedValue));
}
}
I really wish I understood why this does not work. Because if it did work, it would simplify coding, eliminating some of the more mundane aspects of it so you could focus on getting the business logic right. But over the years I have spent many hours trying to get Microsoft widgets to work with marginal success at best. Thus, the point of my rant.
What you don't know can hurt you!
|
|
Reply By:
|
Imar
|
Reply Date:
|
5/20/2008 2:54:01 AM
|
Again, it seems you're not really showing us the while picture here.
I took your example user control, created a Users table with a User_Name column, removed the other two SqlDataSource controls. I then added the User Control to a page, hit F5, chose a new item from the list and the breakpoint in cboUsers_SelectedIndexChanged was hit.
So, the controls work, the principle are OK, but not in your situation. This leads me to believe that things are handled differently in your situation. Maybe you are incorrectly, or too late, loading your dynamic controls. Maybe something else is going wrong.
However, what it is exactly is hard to say as a) you're not showing and explaining us the whole picture, and b) you seem to post a different code snippet from a different situation every time you post here. Remember, all we can see is the stuff you post here.....
Cheers,
Imar
--------------------------------------- Imar Spaanjaars http://Imar.Spaanjaars.Com Everyone is unique, except for me. Author of Beginning ASP.NET 3.5 : in C# and VB, ASP.NET 2.0 Instant Results and Dreamweaver MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
robzyc
|
Reply Date:
|
5/20/2008 3:17:23 AM
|
Are we not coming at this from the wrong angle? Reading this seems like reading one of my posts, where I dont fully understand the ASP.NET framework and application development model.. Would it not be best to work up an understand of the fundamentals of ASP.NET applications THEN try and build user controls and all the "widgets" you want to cut the fat out of your code? Thats what I am doing and its paying dividends..
This is not a flame, but I cant help but feeling there may be an element of "run before you can walk" here?
I mean, we all need to rant now and then, but there are thousands of ASP.NET developers out there, actively using MS Web Controls (they are not called Widgets, see Sam's post). Like I said, I too am new to ASP.NET development, so when it comes to User Controls, guess what I do? Nothing. I wont do them until I have a firm grasp on how pages are constructed, controls are rendered, the PostBack system etc. These are fundamentals and must be mastered first rather than "having a bash" and then blaming the underlying technology/vendor.
Its like trying to do Windows programming without understanding Events..
Just my thoughts, not a flame, just think maybe you should work up rather than down.
Rob http://robzyc.spaces.live.com
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/21/2008 10:50:13 AM
|
Hi Rob,
Thanks for your comments, I don't see them as a flame as you have a legitimate issue. Unfortunately I, like many others, don't often have the time to fully explore all aspects of a development model before I am required to jump in and do something productive with it.
I did discover my problem (I think). Because my user controls were activated with with a PageData.Add method, I believe each time I called the default.aspx web page, the user control was regenerated before the postback methods could be called. An alternative could have been to add each user control to the PageData object at design and set their Visibility attribute to false.
<asp:TableCell ID="PageData" runat="server" HorizontalAlign="center">
<uc2:CEMData ID="CEMData1" runat="server" Visible="true" />
<uc3:CEMDevices ID="CEMDevices1" runat="server" Visible="false" />
<uc4:CEMUsers ID="CEMUsers1" runat="server" Visible="false" />
</asp:TableCell>
Then make them visible as I needed them in a non-postback Load_Page.
But as most of the user controls required data this would add a lot of overhead as each user control is instantiated so I opted to use a separate web page for each task. I need to get a handle on Master Pages as this might do what I want without the overhead.
Now I have to figureout how to get SqlDataSource to Insert, Update and Delete. But I have some more reading to do before I start asking questins. I could rant on about tech books but I'll save that for another time...
What you don't know can hurt you!
|
|
Reply By:
|
samjudson
|
Reply Date:
|
5/22/2008 4:20:14 AM
|
Two things to be aware of regarding creating control manually are :
* you should probably do the creation of controls in the Page_Init event * if you don't give the control the same ID each time event handlers wont be called correctly, although the postback will get triggered (i.e. the page will reload but your event wont get called).
I hope that helps.
/- Sam Judson : Wrox Technical Editor -/
|
|
Reply By:
|
David_0223
|
Reply Date:
|
5/22/2008 3:15:36 PM
|
Sam, I'm not sure what you mean by "creating controls manually".
If you change the name of a control you have to check the event handler statement (MyControl.OnSomeEvent += new EventHandler(EventHandler_Name);) to be sure "EventHandler_Name" is still correct. But I usually let the IDE do it, taking advantages of some of the macros.
What you don't know can hurt you!
|
|
Reply By:
|
samjudson
|
Reply Date:
|
5/22/2008 4:08:09 PM
|
By manually I meant in code, i.e.
MyControl newControl = new MyControl(); newControl.ID = "myControl1"; Page.Controls.Add(newControl);
Without the line in bold events in the control will not be triggered.
I have written the following sample, which works fine for me here:
Control Code: WebControl1.ascx
<asp:ObjectDataSource runat="server" ID="objectSource1" SelectMethod="GetList"
TypeName="WebApplication2.ObjectData">
</asp:ObjectDataSource>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True"
DataSourceID="objectSource1" DataTextField="Name" DataValueField="Index"
onselectedindexchanged="DropDownList1_SelectedIndexChanged">
</asp:DropDownList>
Control Code: WebControl1.ascx.cs
public partial class WebUserControl1 : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Debug.Fail("break here");
}
}
Page Code: Default.aspx
<form id="form1" runat="server">
<div>
<uc1:WebUserControl1 ID="WebUserControl11" runat="server" />
</div>
</form>
Obviously your code will be more complicated than this - but perhaps you can use this simple example as a guide to see what you are doing differently. Once we know what you are doing differently we can try to work out why that is not working.
/- Sam Judson : Wrox Technical Editor -/
|