If you are using AJAX then the only way i have found yet to give an alert to a user on return to the Asynchronous post back is to add an “end request” handler to the PageRequestManager.
In this way you can tell the request manager to run a javascript function on returning from a Asynchronous post back event of AJAX.
Introduction
Most security systems' passwords are case-sensitive. Case sensitivity nearly doubles the number of possible characters that can appear in the password, which makes it harder for nefarious users trying to break into the system. As a result, if a user logging into the system has Caps Lock turned on, they'll enter letters in the opposite case and not be able to login. Because the textboxes that collect user input typically are masked to prevent an onlooker from seeing a user's password, the user typing in her password may not realize that Caps Lock is on. To help prevent this type of user error, many login screens for desktop-based applications display some sort of warning if the user's Caps Lock is on when they start typing in their password.
Unfortunately, such functionality is rarely seen in web applications. A 4Guys reader recently asked me if there was a way to provide such feedback to a user logging into an ASP.NET website. The short answer is, Yes. It is possible to detect whether a user has Caps Lock enabled through JavaScript. Likewise, it's possible to have this client-side logic execute whenever a user starts typing in a particular textbox. With a little bit of scripting, such an interface could be devised.
After thinking about the implementation a bit, I decided to create a compiled server-side control that would emit the necessary JavaScript. This article introduces this control, WarnWhenCapsLockIsOn, and shows how it works and how to use it in an ASP.NET web page. Read on to learn more!
An Overview of the WarnWhenCapsLockIsOn Control's Functionality
The WarnWhenCapsLockIsOn control is designed to display a page developer-specified message if a user types in a specified TextBox control with Caps Lock on. The control extends the Label class so it has the same set of properties as the Label control: Text, Font, Width, CssClass, and so on. Use these properties to configure the message and the message's appearance.
In addition to the Label control's properties, the WarnWhenCapsLockIsOn control also has a TextBoxControlId property, which you must set to the ID of a TextBox control. This property is required. (To provide a Caps Lock warning for multiple TextBox controls on the page, add a WarnWhenCapsLockIsOn control for each TextBox.) If the user starts typing in the specified textbox with the Caps Lock on, the WarnWhenCapsLockIsOn control is displayed. The WarnWhenCapsLockIsOn control is hidden again when one of the following conditions apply:
The user types in the same textbox with Caps Lock off.
The WarnWhenCapsLockIsOn control has been displayed for WarningDisplayTime milliseconds. The WarningDisplayTime property defaults to a value of 2500, meaning that the control will be displayed for 2.5 seconds after the last character with Caps Lock on has been typed. You can lengthen or shorten this property value as needed. A value of 0 displays the warning until the user types in a character without Caps Lock on or after there's a postback.
To provide a warning to the user if Caps Lock is on, then, you'll add this control to the page, set its Text property (and, perhaps, other formatting properties), and indicate the TextBox to "watch" via the control's TextBoxControlId property. That's all there is to it! We'll discuss how to add the WarnWhenCapsLockIsOn control to your ASP.NET website project and look at an end-to-end example in the "Using the WarnWhenCapsLockIsOn Control in an ASP.NET Web Page" section later on in this article.
Initially Hiding the WarnWhenCapsLockIsOn Control
Whenever the ASP.NET page is loaded in the user's browser, the WarnWhenCapsLockIsOn control needs to be hidden so that it does not appear. The WarnWhenCapsLockIsOn control should only appear when the user starts typing in the specified textbox with Caps Lock on. To initially hide the WarnWhenCapsLockIsOn control, I overrided the control's AddAttributesToRender method and added code that set the visibility and display style attributes to "hidden" and "none", respectively.
public class WarnWhenCapsLockIsOn : System.Web.UI.WebControls.Label
{
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
// Add a style attribute that hides this element (by default) writer.AddStyleAttribute(HtmlTextWriterStyle.Visibility, "hidden");
writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
}
}
The effects of these style attribute settings are evinced by the markup sent to the browser. Because the WarnWhenCapsLockIsOn control extends the Label class, it renders as a <span> element with the value of its Text property rendered as the <span> element's inner content, just like the Label control. In the style attribute you can see that the visibility and display settings have been configured to hide the control:
<span id="ID" style="visibility:hidden;display:none;">Value of Text property</span>
We now need to write JavaScript that sets the visibility and display settings to "visible" and "inline" whenever the user types into the corresponding textbox with Caps Lock on.
Executing JavaScript in Response to Typing in a Textbox
It is possible to execute JavaScript in response to a variety of client-side events, such as when the document has loaded, when the user changes the selection of a drop-down list, when an input field receives (or loses) focus, or when the user presses a key. To execute client-side script in response to a user pressing a key, use the onkeypress event like so:
<input type="text" ... onkeypress="action" />
The action can be inline script or a call to a function. In addition to noting that a key has been pressed, JavaScript offers the event object, which includes information such as what key was pressed and whether or not the Shift key was depressed, among other useful tidbits. In short, we need to add an onkeypress client-side event handler to the TextBox control referenced by the WarnWhenCapsLockIsOn control's TextBoxControlId property. The event handler called must determine whether Caps Lock is on or off and show or hide the WarnWhenCapsLockIsOn control in response.
To add client-side event handlers to a server-side Web control use the Attributes collection like so:
WebControlID.Attributes["attribute"] = "value";
The above code adds the markup attribute="value" to the Web control's rendered output. Usually this sort of logic is applied during the PreRender stage of the page lifecycle. Therefore, to implement this functionality I overrode the OnPreRender method in the WarnWhenCapsLockIsOn class (which is fired during the PreRender stage) and added the following code:
public class WarnWhenCapsLockIsOn : System.Web.UI.WebControls.Label
{
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (this.Enabled)
{
/* We need to add two bits of JavaScript to the page:
* (1) The include file that has the JavaScript function to check if Caps Lock is on
* (2) JavaScript that will call the appropriate function in (1) when a key is pressed in the TextBoxControlId TextBox
*/
// (1) Register the client-side function using WebResource.axd (if needed)
if (this.Page != null && !this.Page.ClientScript.IsClientScriptIncludeRegistered(this.GetType(), "skmControls2"))
this.Page.ClientScript.RegisterClientScriptInclude(this.GetType(), "skmValidators", this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "skmControls2.skmControls2.js"));
The GetTextBoxControl method (not shown in this article) returns a reference to the TextBox control specified by the TextBoxControlId property. This referenced TextBox has its Attributes collection updated to include an onkeypress event handler that calls the JavaScript function skm_CheckCapsLock. The skm_CheckCapsLock function (which we'll examine shortly), is passed three input parameters:
event - information about the keypress event, including what key was pressed and whether the Shift key was depressed.
The value of the WarnWhenCapsLockIsOn's ClientID property - we need to supply the client-side id of the WarnWhenCapsLockIsOn control so that it can be displayed or hidden, depending on whether the user has Caps Lock on.
WarningDisplayTime - the number of milliseconds to display the Caps Lock warning; defaults to 2500 milliseconds (2.5 seconds).
The WarnWhenCapsLockIsOn control is one of a few controls in my open-source control library, skmControls2. Another control in the same library is the TextBoxCounter control, which interactively displays how many characters the user has currently typed into a given textbox. (For more information on the TextBoxCounter control, read: Creating a TextBox Word / Character Counter Control.) The TextBoxCounter control requires a bit of JavaScript, and that JavaScript is already defined in a file named skmControls2.js. This file is compiled as an embedded resource in the assembly and is loaded into the ASP.NET page on which the TextBoxCounter or WarnWhenCapsLockIsOn controls are used via a call to the GetWebResourceUrl method. For more information on this technique see: Accessing Embedded Resources through a URL using WebResource.axd.
Because the skmControls2 library already has a JavaScript file, I decided to place the skm_CheckCapsLock function (and ancillary helper functions) there. It is injected into the ASP.NET page in the OnPreRender method (see step 1 in the comments in OnPreRender).
Determining Whether Caps Lock is On
When the keypress event is raised in client-side script, the event object contains information as to what key was pressed and whether the Shift key was depressed (along with whether Alt and Ctrl were depressed). It does not, however, indicate whether Caps Lock was on. The good news is that with a bit of code we can determine whether Caps Lock is on. If the user has entered a capital letter and the Shift key is not depressed, then Caps Lock must be on; likewise, if the user enters a lowercase letter and the Shift key is depressed, then Caps Lock is on.
The skm_CheckCapsLock function determines whether Caps Lock is on and, if so, calls the skm_ShowCapsWarning function, which displays the WarnWhenCapsLockIsOn control for a specified interval. If Caps Lock is not on then the skm_HideCapsWarning function is called, which hides the WarnWhenCapsLockIsOn control. The skm_CheckCapsLock function uses a modified version of a script created by John G. Wang, available online at http://javascript.internet.com/forms/check-cap-locks.html.
function skm_CheckCapsLock( e, warnId, dispTime ) {
var myKeyCode = 0;
var myShiftKey = e.shiftKey;
if ( document.all ) {
// Internet Explorer 4+
myKeyCode = e.keyCode;
} else if ( document.getElementById ) {
// Mozilla / Opera / etc.
myKeyCode = e.which;
}
if ((myKeyCode >= 65 && myKeyCode <= 90 ) || (myKeyCode >= 97 && myKeyCode <= 122)) {
if (
// Upper case letters are seen without depressing the Shift key, therefore Caps Lock is on
( (myKeyCode >= 65 && myKeyCode <= 90 ) && !myShiftKey )
||
// Lower case letters are seen while depressing the Shift key, therefore Caps Lock is on
( (myKeyCode >= 97 && myKeyCode <= 122 ) && myShiftKey )
)
{
skm_ShowCapsWarning(warnId, dispTime);
}
else {
skm_HideCapsWarning(warnId);
}
}
}
The keen reader will note that this check doesn't really identify when Caps Lock is on or off. Rather, it identifies if Caps Lock is on or off when typing in an alphabetic character. If the user types in the number "9" or presses the left arrow, the first conditional statement will evaluate to false. In other words, the skm_ShowCapsWarning or skm_HideCapsWarning functions are only called when the user enters an alphabetic character.
The skm_ShowCapsWarning and skm_HideCapsWarning functions are not shown in this article; you'll have to download the source code to inspect them. They're both fairly straightforward: both reference the WarnWhenCapsLockIsOn control and then set the visibility and display properties to show or hide the warning message. The only trickiness deals with the code that displays the warning for at most a specified number of milliseconds after the user types in with Caps Lock on. Specifically, these functions use the JavaScript setTimeout and clearTimeout methods. For more information on these functions, see the JavaScript Timing Events tutorials at W3 Schools.
Using the WarnWhenCapsLockIsOn Control in an ASP.NET Web Page
The download available at the end of this article includes the complete source code for the WarnWhenCapsLockIsOn controls, as well as a demo ASP.NET website. To use the skmControls2 controls in an ASP.NET website, copy the DLL to the website's /Bin directory and then add the following @Register directive to the tops of the .aspx pages where you want to use the controls:
The demo included in the download has an ASP.NET page that shows using the WarnWhenCapsLockIsOn control in two scenarios: on a stand-alone TextBox and on the Password TextBox in the Login control. Let's look at the stand-alone TextBox example first:
<b>Please enter your name:</b>
<asp:TextBox ID="YourName" runat="server"></asp:TextBox>
<skm:WarnWhenCapsLockIsOn runat="server" ID="WarnOnYourName"
CssClass="CapsLockWarning" TextBoxControlId="YourName"
WarningDisplayTime="5000"><b>Warning:</b> Caps Lock is on.</skm:WarnWhenCapsLockIsOn>
The declarative markup above shows three controls: a TextBox (YourName); a WarnWhenCapsLockIsOn control; and a Button Web control. The WarnWhenCapsLockIsOn control is configured to display the message "Warning: Caps Lock is on" when the user types into the YourName textbox with Caps Lock on. It uses the CSS class CapsLockWarning for its styling, which I've defined on the page; the class specifies a light yellow background, padding, centered text, and a red border. The warning message is displayed for (at most) five seconds.
The following screen shot shows the demo page in action. Note that when Caps Lock is on and an alphabetic character is typed, the warning is displayed. This warning immediately disappears when Caps Lock is turned off and another alphabetic character is typed, or after five seconds, whatever comes first.
This demo also shows how to apply the WarnWhenCapsLockIsOn control to the Password TextBox of a Login control. Start by adding a Login control to the page and then, from the Designer, select the "Convert to Template" from its smart tag. This will convert the Login control into a template, at which point you can add the WarnWhenCapsLockIsOn control in the Login user interface as needed, referencing the Password TextBox (whose ID property is "Password"). Be sure to put the WarnWhenCapsLockIsOn control within the Login control's template so that it can "see" the Password TextBox.
참고 Visual Basic .NET에서 클래스를 만드는 데 대한 배경 설명을 보려면 클래스의 이해를 참조하십시오. Visual C# .NET의 경우에는 클래스를 참조하십시오.
템플릿 클래스를 만들려면
System.Web.UI 네임스페이스의 ITemplate 인터페이스를 구현하는 새 클래스를 만듭니다.
필요한 경우, 클래스에서 만들 템플릿의 형식(ItemTemplate, AlternatingItemTemplate 등)을 결정할 때 사용되는 값을 클래스의 생성자에 전달합니다.
팁 생성자에 템플릿 형식을 전달할 때 형식 안전성을 유지하려면 ListItemType 형식을 사용하여 생성자에 매개 변수를 추가하면 됩니다. ListItemType 열거형에서는 Repeater, DataList 및 DataGrid 컨트롤에 대해 사용 가능한 템플릿 형식을 정의합니다.
ITemplate 인터페이스의 유일한 멤버인 InstantiateIn 메서드를 클래스에 구현합니다. 이 메서드를 통해 텍스트 및 컨트롤의 인스턴스를 지정된 컨테이너에 삽입할 수 있습니다.
InstantiateIn 메서드에서 템플릿 항목에 대한 컨트롤을 만들고 속성을 설정한 다음 부모의 Controls 컬렉션에 추가합니다. InstantiateIn 메서드에 전달된 참조를 통해 부모 컨트롤에 액세스할 수 있습니다.
참고Controls 컬렉션에 정적 텍스트를 직접 추가할 수는 없지만, Literal 컨트롤 또는 LiteralControl 컨트롤 등의 컨트롤을 만들고 Text 속성을 설정한 다음 이 컨트롤을 부모 컬렉션에 추가할 수는 있습니다.
다음 예제에서는 일부 정적 텍스트("Item number:") 및 카운터를 표시하는 완전한 템플릿 클래스를 보여 줍니다. 카운터는 클래스에 대해 itemcount라는 공유 또는 정적 값(사용하는 언어에 따라 다름)으로 보존되며 새 항목이 만들어질 때마다 크기가 증가합니다.
클래스에서는 만들어지는 템플릿의 형식을 나타내기 위해 ListItemType 열거형 값을 받는 명시적 생성자를 정의합니다. 만들어지는 템플릿의 형식에 따라 코드에서 서로 다른 종류의 컨트롤이 만들어지고 이 컨트롤은 부모 컨트롤의 Controls 컬렉션에 추가됩니다. 마지막으로, 대체 항목 템플릿에 대해 서로 다른 배경색을 가진 HTML 테이블이 만들어집니다.
' Visual Basic
Private Class MyTemplate
Implements ITemplate
Shared itemcount As Integer = 0
Dim TemplateType As ListItemType
Sub New(ByVal type As ListItemType)
TemplateType = type
End Sub
Sub InstantiateIn(ByVal container As Control) _
Implements ITemplate.InstantiateIn
Dim lc As New Literal()
Select Case TemplateType
Case ListItemType.Header
lc.Text = "<TABLE border=1><TR><TH>Items</TH></TR>"
Case ListItemType.Item
lc.Text = "<TR><TD>Item number: " & itemcount.ToString _
& "</TD></TR>"
Case ListItemType.AlternatingItem
lc.Text = "<TR><TD bgcolor=lightblue>Item number: " _
& itemcount.ToString & "</TD></TR>"
Case ListItemType.Footer
lc.Text = "</TABLE>"
End Select
container.Controls.Add(lc)
itemcount += 1
End Sub
End Class
// C#
public class MyTemplate : ITemplate
{
static int itemcount = 0;
ListItemType templateType;
public MyTemplate(ListItemType type)
{
templateType = type;
}
public void InstantiateIn(System.Web.UI.Control container)
{
Literal lc = new Literal();
switch( templateType )
{
case ListItemType.Header:
lc.Text = "<TABLE border=1><TR><TH>Items</TH></TR>";
break;
case ListItemType.Item:
lc.Text = "<TR><TD>Item number: " + itemcount.ToString() +
"</TD></TR>";
break;
case ListItemType.AlternatingItem:
lc.Text = "<TR><TD bgcolor=lightblue>Item number: " +
itemcount.ToString() + "</TD></TR>";
break;
case ListItemType.Footer:
lc.Text = "</TABLE>";
break;
}
container.Controls.Add(lc);
itemcount += 1;
}
}
' Visual Basic
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Repeater1.HeaderTemplate = New MyTemplate(ListItemType.Header) Repeater1.ItemTemplate = New MyTemplate(ListItemType.Item) Repeater1.AlternatingItemTemplate = _ New MyTemplate(ListItemType.AlternatingItem) Repeater1.FooterTemplate = New MyTemplate(ListItemType.Footer)
SqlDataAdapter1.Fill(DsCategories1)
Repeater1.DataBind()
End Sub
// C#
private void Page_Load(object sender, System.EventArgs e)
{
Repeater1.HeaderTemplate = new MyTemplate(ListItemType.Header); Repeater1.ItemTemplate = new MyTemplate(ListItemType.Item); Repeater1.AlternatingItemTemplate = new MyTemplate(ListItemType.AlternatingItem); Repeater1.FooterTemplate = new MyTemplate(ListItemType.Footer);
sqlDataAdapter1.Fill(dsCategories1);
Repeater1.DataBind();
}
템플릿에 데이터 바인딩 추가
템플릿 클래스 안에서 데이터에 액세스할 수 있는 방법은 클래스를 만드는 방법에 따라 다양합니다. 이 중에서 페이지 아키텍처 자체에서 데이터 바인딩을 구현하는 것이 가장 좋습니다. 템플릿에 컨트롤을 추가하면 이러한 컨트롤의 DataBinding 이벤트에 대한 처리기도 추가됩니다. 이 이벤트는 템플릿 항목과 해당 템플릿과 관련된 컨트롤이 모두 만들어진 후에 발생하며 데이터를 페치하여 컨트롤에서 사용할 수 있도록 합니다.
참고 템플릿에 컨트롤을 만들 때 디자인 타임에 템플릿을 정의할 때처럼 데이터 바인딩 식을 문자열로 포함할 수 없습니다. 데이터 바인딩 식은 템플릿이 만들어지기 전에 발생하는 페이지 처리 과정 단계에서 코드로 변환되기 때문입니다.
DataBinding 이벤트에 대한 처리기에서 컨트롤의 내용을 조작할 수 있습니다. 필수적인 것은 아니지만, 보통 임의의 위치에서 데이터를 페치(fetch)하여 컨트롤의 Text 속성에 할당합니다.
참고 Web Forms 페이지에서의 데이터 바인딩 작업에 대한 배경 설명은 Web Forms 데이터 바인딩을 참조하십시오.
동적 템플릿에 데이터 바인딩을 추가하려면 다음 작업을 수행해야 합니다.
템플릿에서 만든 컨트롤에 데이터 바인딩 이벤트 처리기를 추가합니다.
바인딩 대상이 되는 처리기를 만듭니다. 바인딩할 데이터를 이 처리기에서 가져온 다음, 바인딩되는 컨트롤의 해당 속성에 할당합니다.
데이터 바인딩 이벤트 처리기를 추가하려면
동적 템플릿에 컨트롤을 만든 후에 표준 명령을 사용하여 컨트롤의 DataBinding 이벤트를 나중에 만들 메서드에 바인딩합니다.
' Visual Basic
Dim lc As New Literal()
Case ListItemType.Item
lc.Text = "<TR><TD>"
AddHandler lc.DataBinding, AddressOf TemplateControl_DataBinding
// C#
Literal lc = new Literal();
case ListItemType.Item:
lc.Text = "<TR><TD>";
lc.DataBinding += new EventHandler(TemplateControl_DataBinding);
break;
이 예제에서 리터럴 컨트롤의 Text 속성에 추가하는 텍스트는 이전의 예제에 나온 텍스트와는 다릅니다. 여기에는 표 행의 시작 부분과 항목 템플릿에 대한 셀만 포함되어 있습니다. 데이터 바인딩 이벤트 처리기에서 셀과 행을 완성합니다.
다음 단계에서는 컨트롤에 데이터가 바인딩될 때 호출되는 이벤트 처리기를 만듭니다.
DataBinding 이벤트에 대한 처리기를 만들려면
템플릿 클래스를 구성하며 이 클래스의 InstantiateIn 등과 같은 다른 메서드와 동일한 수준의 역할을 수행할 메서드를 만듭니다. 처리기의 이름은 이벤트 처리기를 바인딩할 때 사용했던 이름과 같아야 합니다. 이 이벤트에는 다음과 같은 서명이 있어야 합니다.
Create a very simple page in ASP.NET 2.0, add a TreeView control and set ShowLines=true; now browse the page with Internet Explorer 7: you'll very likely see something like this:
In IE 6 this looks good...
The point is that Internet Explorer 7 changes the boxing model: now a box that's too small to accomodate ita content won't stretch like it does on all other browsers including IE6, it will try to stay as small as possible. The problem in this case is that the DIV tags generated by the control are just 1 pixel height, which was working fine until now. Here is how the "View source" for the page above looks:
As you can see, the first DIV tag contains a style definition with "height:1px"; that's the problem.
And now, here is how we can sort this out:
Create a new style definition in your page (or create an external .css file and link it in your pages, pedending on your needs)
Add the following class definition: ".tree td div {height: 20px !important}" (of course without quotation marks)
In your TreeView component add a referende to CssClass="tree"
Note that normally the style defined in the DIV takes precedence over the style defined at page level (or external .css file), but since in this case we need to override that setting, we can use the !important CSS directive; here is how the modified source looks like:
Uhm... weird, I tested them before posting... Matthew, are you sure you are using the right values? If you copy the code above and test in a sample page, what do you get?
True... I guess that's because those dotted lines are actually images (if you use IE developer toolbar you can quickly highlight them all) and are not easilly customizable, unless maybe you use your own set of images for the control. I tried to tweak it with some stylesheet properties but with no luck so far... :-(
Solution is a big help...but..seems to have further problems if the treeview display properties are altered. For example if the Vertical NodeSpacing or BoderStyle Setting are changed from default the problem continues. I have tried to compensate the height number with border width changes, but no success. Does anyone have a solution for thios please?
Also having same problem as Matthew Weaver. I still get broken lines. I have set the CssStyle on the TreeView component. I have also removed all other of the other TreeView display properties.
I have just loaded the new IE8. Unfortunately, it seem to have the same problem as described above. Does anyone have a work-around or a treeview which works??
thanks for your solution. It worked fine surprisingly. I am facing another issue by having checkboxes enabled in my treeview. When i try to expand a subnode having checkbox already enabled and having child nodes, it renders incorrectly on postback and displays in the root node level. Please reply soon with your inputs.
Unfortunately, this didn't work for me :-(. I will try to explain my scenario with a small example. Lets say i have a tree like a<-b<-c (a is parent to b & b is parent to c). When i check the checkbox for node 'a' and then click + sign to expand, the node 'b' is displayed and added NOT as a child to node 'a' but in the same root level as node 'a' exists. Same is the case when node 'b' is checked and expanded to get node 'c'.
When i click on the node 'b' it refreshes the grid and the tree is formed correctly i.e. node 'b' child node of 'a'.
Vinod, this is a completely different problem, not really what's described in the post (I guess that's why the solution does not work for you)... the indentation level has nothing to do with the "dotted" line which is just a "cosmetic" thing.
What you describe sounds like either a coding issue (or maybe a bug in the control, it cannot be excluded at the moment) so I think you should really consider opening a call with CSS (http://support.microsoft.com) and someone from my team (maybe me, if you're based in EMEA) will have a look, best working on a sample to repro the problem.
I tracked it down to may master page's style sheet setting a vertical-align: top; to the region containing the treeview. This still left gaps in the lines... to fix this I just added vertical-align: baseline; to the treeviews style & that fixed it...
This took me hours to find... hope it helps someone else.
Response.End의 경우 Response.End 대신 HttpContext.Current.ApplicationInstance.CompleteRequest 메서드를 호출하여 Application_EndRequest 이벤트에 대한 코드 실행을 무시합니다.
•
Response.Redirect의 경우 endResponse 매개 변수에 대해 false를 전달하여 Response.End를 내부적으로 호출하지 않도록 하는 Response.Redirect(String url, bool endResponse) 오버로드를 사용합니다. 예는 다음과 같습니다.
Thanks Jeffrey, this works just fine. It is perhaps worth noting that Attributes["class"] = "myCSSClass" uses C# syntax. VB is Attributes("class") = "myCSSClass". This trips me up regularly - I much prefer C# syntax, but am sometimes forced to use VB.
> Alfred, > Any time you want to add any attribute that may not be included in the > code, just use HtmlTable.Attributes["class"] = "myCSSClass"; > This will work for any attribute. > > Best regards, > Jeffrey Palermo > > "Alfred Salton" <> wrote in message > news:2004062721504216807%alfredsalton@hotmailcom.. . >> Can anyone show me how to set the css class of an HtmlTable control in >> code on the server? >> >> I can't find any indication that the css class is a property of the >> HtmlTable, HtmlTableRow and HtmlTableCell classes. I'm getting the >> uncomfortable feeling that this can't be done, even though it seems >> incredible to me!
In this article I have tried to cover a cycle of developing a web report using Crystal Report in .NET 2005. I haven't put any effort for the butification of the report. The report is just showing the Employee master data from the Northwind database of SQL Server.
The report is build on XML Schema and the data and binded the report at runtime.
Requirements
Microsoft C#.NET 2005
Windows 2000/2003/XP
SQL Server 2000/2005(Optional). I have used SQL Server to fecth data. If in case SQL Server is not available then change the connection string in web.config and connection related syntax in Default.aspx.cs.
Creating your own Report
To start with Reports, you need start .NET 2005 Development Studio.
Start a new ASP .NET Web site, Choose Location as "File System" and provide a path.
Perform "Add New Item", choose "XML Schema". Add elements as the picture below.
After saving the elements will look like this, in the XML Editor
5. Open the Default.aspx.cs file and paste the following codes.
Collapse
using System; using System.Data; using System.Configuration; 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; //--SqlClient for SqlConnection and etc. using System.Data.SqlClient; //--for CrystalReports's ReportDocument. using CrystalDecisions.CrystalReports.Engine; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //--Sql string String strCmd = ""; strCmd += "Select EmployeeID, LastName, FirstName, Title, BirthDate, "; strCmd += "Address, City, Region, PostalCode, Country, HomePhone "; strCmd += "From Employees "; //--Opening Sql Connection string strConn = ConfigurationManager.AppSettings["connectionstring"]; SqlConnection sqlConn = new SqlConnection(strConn); DataSet ds = new DataSet(); SqlDataAdapter da = new SqlDataAdapter(strCmd, sqlConn); //--this statement is very important, here the table name should //--match with the XML Schema table name da.Fill(ds, "Employees"); //--Closing Sql Connection sqlConn.Close(); //--(Optional) I have used it to disable the properties CrystalReportViewer1.DisplayGroupTree = false; CrystalReportViewer1.HasCrystalLogo = false; //--Initializing CrystalReport ReportDocument myReportDocument; myReportDocument = new ReportDocument(); myReportDocument.Load(Server.MapPath("Employees.rpt")); myReportDocument.SetDataSource(ds); //--Binding report with CrystalReportViewer CrystalReportViewer1.ReportSource = myReportDocument; CrystalReportViewer1.DataBind(); } }
6. Open the Web.config file and change the connection string under <appSettings> as per your machine (ip address, username, password).
</appSettings> If in case the file is not available then perform "Add New Item", choose "Web Configuration File", and follow the same thing.
7. Using the script
Just to check wheather Employees master table is available with data . Open SQL Server Query Analyzer . Copy the scripts . Paste into Query Analyzer . Press F5 to execute
--------------------------------- -----Using Database --------------------------------- Use Northwind; --------------------------------- -----Selecting data from Table --------------------------------- Select EmployeeID, LastName, FirstName, Title, BirthDate, Address, City, Region, PostalCode, Country, HomePhone From Employees;
7. Now build the Web project. Press F5/Ctrl F5 to view the report. Hope everything will go fine.
About Suranjan Nandi
Suranjan Nandi has 7 years of working experience in Software Development using Microsoft Technology. During this period he was involved with .NET Technologies, COM, Client Server Architecture, Multi-tier Architecture, Crystal Reports, Database Analysis & Designing in Microsoft Environment.
Click here to view Suranjan Nandi's online profile.
This article will enhance your vision on the usage of Robustness Analysis in conjunction with Model View Controller, using UML with application in ASP.NET. This article is a sequel to my articles on Architecture and Design with ASP.NET.
UpdatePanel has always given us some sort of error handling during partial postbacks (or, if you want to use the new official term, async postbacks). In previous CTPs, you could handle a page error event and perform your own error handling (which normally consisted in some form of logging). The problem previous versions had was related with the way that the error message was shown in the client side (by default, it showed an alert message box, though you could define a limited error template). The current release give us a lot more options as I'll show you in this post.
If you don't do anything, when you get an error during partial postback you'll get a simple alert message box showing you the error message associated with the exception you had in the server. As we all agree, this is not the best info to show to our users; it's also not a good idea to show a standard error message. If we don't mind showing an alert message in the client, then we can start by handling the AsyncPostBackError event generated by the ScriptManager control in order to customize the error message returned from the server. Here's a simple page that shows this approach:
<%@ 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"> void handleClick(object sender, EventArgs e) { int a = 0; int res = 10 / a; } void HandleError(object sender, AsyncPostBackErrorEventArgs e) { //here we could log the error, and see which exception we're getting in order to set a specific error message //in this case, I'm just returning the current date/hour back manager.AsyncPostBackErrorMessage = "Ooops...error occurred: " + DateTime.Now.ToString(); } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager runat="server" ID="manager" OnAsyncPostBackError="HandleError"> </asp:ScriptManager> <asp:UpdatePanel runat="server" ID="panel"> <ContentTemplate> <asp:Button runat="server" ID="bt" Text="gerar erro no servidor" OnClick="handleClick" /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html>
As you can see, when the user clicks the button, he'll get a divide by zero exception error on the server side. The previous page shows how you could log the error and return a friendly error message back to the client (the AsyncPostBackErrorMessage was introduced in this version and lets us define the error message which is returned to the client when an exception occurs on the server side). If you run the page, you'll notice that you'll still get the alert message, but this time, it'll show our fridendly error message.
If you want, you can drop the standard alert message and show the error in any way you see fit. To illustrate the steps necessary to perform this operation, I'll start by adding a DIV ccontrol that will be used as a place holder for showing the error returned from the server:
<div id="err"></div>
The next thing we need to do is to handle the endRequest event which is fired by the PageRequestManager object which is present in all the pages that use UpdatePanels:
I start by adding a method that will handle the endRequest event by using the add_endRequest method over the Sys.WebForms.PageRequestManager global object. The method starts by checking if there's an error (by using the get_error method) and, when it finds one, it gets its description (through the description field) and sets the errorHandled field of the EventArgs object used to true so that the default alert message isn't shown to the user. Though the previous code is really simple, there's nothing preventing you from using the toolkit behaviors to get similar results to the ones that we had in the previous CTPS (btw, you can also stop processing the server side error event if you don't need logging and do everything in the client side: you're the one that need to decide on what's best here!).
For those that want to show a default error page, then there's still one additional property exposed by ScriptManager which you'll like: AllowCustomerErrors. When you set this property to true, you're saying that ScriptManager should check for a custom error page associated with the current error an show it to the user. To illustrate its usage, lets start by adding the following to the web.config file:
First, you should note that you should never use a Server.Transfer instruction on an ajax page. I'm using it since it's simplest way I could think of getting a known 404 error. Now, back to the important things: the AllowCustoErrors property. Since i've set it to true, when ScriptManager handles an exception during an async postback, it'll read the config file and see if there's any error page associated with the current error. If there is, it'll just send an AJAX message to client which instructs the browser to redirect the user to the desired page.
As you have seen, there's now a lot more control over the way exceptions are handled during a partial postback request. You do have to write more code than in the previous versions, but it's also true that the current release is a lot more flexible than the previous one.
atlas 에서는 <ErrorTemplate> 에다가 설정 해놨었는데, 조금 바뀌었습니다.
예제에는 DIV 로 배경색 바꿔서 div 로 처리하는데
저같은 경우는 masterPage 에다 ajaxToolkit 에 있는 ModalPopupExtender 으로
처리했습니다.
Customizing Error Handling for UpdatePanel Controls
Introduction
When an error occurs during partial-page updates in UpdatePanel controls, by default a script alert box is displayed with an error message. This tutorial shows you how to customize how the error is presented to the user and what information the message contains.
You can see the code in action in this tutorial by clicking the Run It buttons. To implement the procedures in your own development environment you need:
Visual Web Developer Express Edition or Visual Studio 2005.
The latest release of Microsoft ASP.NET AJAX installed and configured. For more information, see Installing ASP.NET AJAX.
An ASP.NET AJAX Web site.
To customize error handling in server code
Create a new page and switch to Design view.
In the AJAX Extensions tab of Toolbox, double-click the ScriptManager control and the UpdatePanel control to add them to the page.
Add two TextBox controls, a Label control, a Button control, and some text inside of the UpdatePanel control. Set the text of the button to Calculate.
Your page will look like the following:
Double-click the Calculate button and add the following code for its event handler.
CS
protected void Button1_Click(object sender, EventArgs e){ try { int a = Int32.Parse(TextBox1.Text); int b = Int32.Parse(TextBox2.Text); int res = a / b; Label1.Text = res.ToString(); } catch (Exception ex) { if (TextBox1.Text.Length > 0 && TextBox2.Text.Length > 0) { ex.Data["ExtraInfo"] = " You can't divide " + TextBox1.Text + " by " + TextBox2.Text + "."; } throw ex; } }
VB
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Try Dim a As Int32 a = Int32.Parse(TextBox1.Text) Dim b As Int32 b = Int32.Parse(TextBox2.Text) Dim res As Int32 = a / b Label1.Text = res.ToString() Catch ex As Exception If (TextBox1.Text.Length > 0 AndAlso TextBox2.Text.Length > 0) Then ex.Data("ExtraInfo") = " You can't divide " & _ TextBox1.Text & " by " & TextBox2.Text & "." End If Throw ex End TryEnd Sub
The event handler code contains a try-catch statement. In the try block, the code divides the values from the text boxes. If the operation fails, code in the catch block adds the extra string information ExtraInfo to the exception and then rethrows the exception without handling it.
Switch to Design view and select the ScriptManager control.
In the toolbar of the Properties window, click the Events button and then double-click the AsyncPostBackError box to create a handler for that event.
Add the following code to the AsyncPostBackError event handler.
The code checks whether the ExtraInfo data item was defined for the exception. If so, the AsyncPostBackErrorMessage property is set to the string value. Otherwise, a default error message is created.
Save your changes and then press CTRL+F5 view the page in a browser.
Add a number greater than zero to each text box and click the Calculate button to demonstrate a successful postback.
Change the second text box input to 0 and click the Calculate button to create an error condition.
The browser displays a message box that contains the message set in the server code.
note
The style of the alert message box depends on what browser you are using, but the message is the same in all browsers.
To see the full example in action, click the Run It button below.
The preceding procedure demonstrated how to customize errors during partial-page rendering by using setting properties of the server ScriptManager control. The following procedure builds on the customization by using the client PageRequestManager class to display the error in a <div> element instead of using the default browser alert message box.
To customize error handling in client script
In the page you created earlier, switch to Source view
The markup includes elements that you can use to display partial-page rendering errors. It defines a <div> element named AlertDiv that contains two other <div> elements. One of the nested <div> elements contains an <input> control that will enable users to hide the <div>.
Add the following style markup in the <head> element.
The styles make the error information stand out visually from the rest of the page content.
Switch to Design view and verify that your page looks like the following:
In the drop-down list at the top of the Properties window, select the DOCUMENT element (which represents the <body> element on the page) and set its Id property to bodytag.
Switch to Source view.
Add the following <script> block anywhere after the <asp:ScriptManager> element.
CS
<script type="text/javascript" language="javascript">var divElem = 'AlertDiv';var messageElem = 'AlertMessage';var bodyTag = 'bodytag';Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);function ToggleAlertDiv(visString){ if (visString == 'hidden') { $get(bodyTag).style.backgroundColor = 'white'; } else { $get(bodyTag).style.backgroundColor = 'gray'; } var adiv = $get(divElem); adiv.style.visibility = visString;}function ClearErrorState() { $get(messageElem).innerHTML = ''; ToggleAlertDiv('hidden'); }function EndRequestHandler(sender, args){ if (args.get_error() != undefined) { var errorMessage; if (args.get_response().get_statusCode() == '200') { errorMessage = args.get_error().message; } else { // Error occurred somewhere other than the server page. errorMessage = 'An unspecified error occurred. '; } args.set_errorHandled(true); ToggleAlertDiv('visible'); $get(messageElem).innerHTML = errorMessage; }}</script>
VB
<script type="text/javascript" language="javascript">var divElem = 'AlertDiv';var messageElem = 'AlertMessage';var bodyTag = 'bodytag';Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);function ToggleAlertDiv(visString){ if (visString == 'hidden') { $get(bodyTag).style.backgroundColor = 'white'; } else { $get(bodyTag).style.backgroundColor = 'gray'; } var adiv = $get(divElem); adiv.style.visibility = visString;}function ClearErrorState() { $get(messageElem).innerHTML = ''; ToggleAlertDiv('hidden'); }function EndRequestHandler(sender, args){ if (args.get_error() != undefined) { var errorMessage; if (args.get_response().get_statusCode() == '200') { errorMessage = args.get_error().message; } else { // Error occurred somewhere other than the server page. errorMessage = 'An unspecified error occurred. '; } args.set_errorHandled(true); ToggleAlertDiv('visible'); $get(messageElem).innerHTML = errorMessage; }}</script>
This script does the following:
Defines a handler for the endRequest event of the PageRequestManager class. In the handler, the code displays the AlertDiv<div> element if there is an error condition.
Defines the ToggleAlertDiv function, which hides or shows the AlertDiv element and changes the color of the page based if there was an error condition.
Defines the ClearErrorState function, which hides the error message UI.
Save your changes and then press CTRL+F5 view the page in a browser.
Add a number greater than zero to each text box and click the Calculate button to demonstrate a successful postback.
Change the second text box input to 0 and click the Calculate button to demonstrate an error condition.
The custom AlertDiv element is displayed instead of default alert message box. The following figure shows an example of the error condition.
To see the full example in action, click the Run It button below.
This tutorial showed ways you can extend error handling during partial-page rendering by writing JavaScript code. In server code you can customize error handling by using the AsyncPostBackErrorMessage property and the AsyncPostBackError event of the ScriptManager control. In client code you can customize error handing by using the endRequest event of the PageRequestManager class.
This topic is ASP.NET AJAX pre-release documentation and is unsupported by Microsoft. Blank topics are included as placeholders and existing content is subject to change in future releases.
N.B.: DO NOT put a space between <span> and <div> tags, if not it does not work properly in Firefox... That is what I found, don't ask me why. Yes, it is strange, I am still looking for an answer... :)
// Copyright (C) 2002 Mark Pasternak//// This software is provided 'as-is', without any express or implied// warranty. In no event will the authors be held liable for any damages// arising from the use of this software.//// Permission is granted to anyone to use this software for any purpose,// including commercial applications, and to alter it and redistribute it// freely, subject to the following restrictions://// 1. The origin of this software must not be misrepresented; you must not// claim that you wrote the original software. If you use this software// in a product, an acknowledgment in the product documentation would be// appreciated but is not required.// 2. Altered source versions must be plainly marked as such, and must not be// misrepresented as being the original software.// 3. This notice may not be removed or altered from any source distribution.//// Mark Pasternak (mark.pasternak@universum.se)// 데브피아 ASP.NET 자료실에서 퍼온 파일 다운로드 클레스입니다.// 요청하신 분이 계셔서 간단한 주석을 달았습니다.//// 주석 첨부 : 조성진 (http://powerof.net)using System;using System.Web;using System.IO;namespace MarkPasternak.Utility{ /// <summary> /// The HttpResponse.WriteFile method does not work very well with large files since it reads /// the whole file to memory at once. This may crash the ASP.NET worker process if the file is too big. /// This helper class uses buffers and continuously checks if the client is connected before it sends any output. /// /// HttpResponse.WriteFile 메소드는 아주 큰 파일을 전송하는 경우 잘 동작하지 않습니다. /// 왜냐면 이 메소드는 전송할 파일을 메모리로 한번에 모두 읽어드리기 때문에 /// 전송할 파일이 크다면 서버에 많은 부담을 줍니다. 심각한 경우는 ASP.NET 프로세스가 죽는 경우도 생기죠. /// 다음의 클레스는 버퍼를 이용해 파일을 읽고 전송하기 때문에 /// 기존 HttpResponse.WriteFile 메소드의 문제를 해결해줍니다. /// 그리고 클라이언트와의 연결을 계속 점검하기때문에 클라이언트에서 파일전송을 /// 취소하거나 다른 이유로 연결이 끊길경우 더이상 파일을 전송하지 않습니다. /// </summary> public class WriteFileHelper { private int m_bufferSize=4096; //버퍼크기를 4메가로 지정 private HttpContext Context; public EventHandler DownloadCancelled; public EventHandler DownloadCompleted; public WriteFileHelper() { Context = HttpContext.Current; } /// <summary> /// Sets and gets the size of the buffer that is used when a file is read to memory. /// A larger buffer will require more memory, but will on the other hand make /// it less resource intensive to send a file. Experiment to find a good balance. /// </summary> /// 위에서 m_bufferSize가 4096으로 기본적으로 설정되지만 /// 원한다면 이 속성을 이용해 버퍼크기를 변경할수 있다. public int BufferSize { set{m_bufferSize=value;} get{return m_bufferSize;} } // 사용자자 파일 전송을 취소하거나 어떤 이유로 클라이언트와 연결이 끈기면 // 이 메소드가 호출됩니다. // 이 클레스 외부에서 DownloadCancelled 의 이벤트 헨들러를 지정하면 // 이 메소드가 호출될때 임의의 처리를 할수 있습니다. protected void OnDownloadCancelled() { if (DownloadCancelled != null) // 헨들러가 지정되 있다면 DownloadCancelled(null, null); } // 파일전송이 완료되면 이 메소드가 호출됩니다. // 이 클레스 외부에서 DownloadCompleted 의 이벤트 헨들러를 지정하면 // 이 메소드가 호출될때 임의의 처리를 할수 있습니다. protected void OnDownloadCompleted() { if (DownloadCompleted != null) // 헨들러가 지정되 있다면 DownloadCompleted(null, null); } /// <summary> /// Writes a file to the Response Stream /// </summary> /// <param name="filePath">A Path to a file</param> /// 전송할 파일의 경로를 인자로 이 메소드를 호출하면 /// 클라이언트로 파일을 보냅니다. /// 그러나 이 메소드대신 다음에 나오는 /// WriteFileToResponseStreamWithForceDownloadHeaders 메소드를 사용하는게 더 편리합니다. /// 그런 이유로 이 메소드는 별로 사용할 일이 없을듯 하군요 public void WriteFileToResponseStream(string filePath) { if(!File.Exists(filePath)) // 요청한 파일이 없으면 에러를 일으킨다. throw new Exception("File Path does not exist : " + filePath); // 클라이언트로 파일을 전송한다. WriteBinaryFile_Internal(filePath); } /// <summary> /// Writes a file to the Response Stream and adds the headers s장the "Save As" dialog is presented to the user /// </summary> /// <param name="filePath">A Path to a file</param> /// 전송할 파일의 경로를 인자로 이 메소드를 호출하면 /// 클라이언트로 HTTP 헤더를 첨부해서 파일을 전송합니다. /// 첨부한 헤더로 인해 클라이언트에는 '열기','저장', '취소' 버튼이 있는 /// 대화상자가 열립니다. public void WriteFileToResponseStreamWithForceDownloadHeaders(string filePath) { if(!File.Exists(filePath)) // 요청한 파일이 없으면 에러를 일으킨다. throw new Exception("File Path does not exist : " + filePath); Context.Response.Clear(); // 해더를 추가한다 Context.Response.ContentType = "application/octet-stream"; Context.Response.AddHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(filePath)); Context.Response.AddHeader("Content-Length", new FileInfo(filePath).Length.ToString()); // 클라이언트로 파일을 전송한다. WriteBinaryFile_Internal(filePath); } // 실질적인 파일전송을 담당하는 메소드 private void WriteBinaryFile_Internal(string filePath) { Context.Response.Buffer=false; // 버퍼링을 하지 않는다. FileStream inStr = null; byte[] buffer = new byte[m_bufferSize]; // 파일을 읽어드릴 버퍼 long byteCount; try { inStr = File.OpenRead(filePath); // 파일을 연다. // m_bufferSize 크기 만큼씩 파일 내용을 차례대로 읽어들인다. while ((byteCount = inStr.Read(buffer, 0, buffer.Length)) > 0) { // 클라이언트가 연결되 있는지 검사한다. // 즉, 사용자가 파일전송을 중간에 취소하거나 // 다른 이유로 연결이 끈기면 IsClientConnected가 talse가 된다. if(Context.Response.IsClientConnected) { // 버퍼에 담긴 데이터를 클라이언트로 전송한다. Context.Response.OutputStream.Write(buffer, 0, buffer.Length); Context.Response.Flush(); } else { // 전송이 취소 됐음을 알리는 이벤트를 발생시킨다. OnDownloadCancelled(); return; } } OnDownloadCompleted(); // 전송 완료 이벤트를 발생시킨다. } catch(Exception ex) { throw ex; } finally { inStr.Close(); Context.Response.End(); } } }}
Comments
# Anothr feed track -A developer's strayings
One new subscriber from Anothr Alerts
# Lineas entrecortadas en el TreeView ASP.NET
Para poder ver las líneas que unen los nodos en un TreeView, hice uso de las siguientes propiedades LineImagesFolder
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
The listed changes had no affect. I still get broken vertical lines with IE7 and FF.
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Uhm... weird, I tested them before posting... Matthew, are you sure you are using the right values? If you copy the code above and test in a sample page, what do you get?
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Matthew Weaver prolly forgot this step:
In your TreeView component add a referende to CssClass="tree"
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Excellent info 2nd link on goog
Thanks!!!
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Awesome. Worked like a charm. I was getting sick of looking at those broken lines :)
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Excellent job :) the only reason i wasn't using the css adapted treeview was for the lines.
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Superb! I've been trying to sort out these gaps for months...
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
thanks for the tip!
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
thanks a lot! I wouldn't find out..
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Greate respect for solve this
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Great post, I have been looking into this myself and also figured out the 1px height problem but couldn't solve it.
Thx for your post!
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
The solution works great.
Unfortunately, lines break again when you set treeview's NodeWrap property to true, and a treeview item spans across multiple lines.
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
True... I guess that's because those dotted lines are actually images (if you use IE developer toolbar you can quickly highlight them all) and are not easilly customizable, unless maybe you use your own set of images for the control. I tried to tweak it with some stylesheet properties but with no luck so far... :-(
Let's see if I can come up with something useful
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Solution is a big help...but..seems to have further problems if the treeview display properties are altered. For example if the Vertical NodeSpacing or BoderStyle Setting are changed from default the problem continues. I have tried to compensate the height number with border width changes, but no success. Does anyone have a solution for thios please?
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Also having same problem as Matthew Weaver. I still get broken lines. I have set the CssStyle on the TreeView component. I have also removed all other of the other TreeView display properties.
Does anyone have a solution?
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
I have just loaded the new IE8. Unfortunately, it seem to have the same problem as described above. Does anyone have a work-around or a treeview which works??
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Awesome!!! it works great surprisingly :)
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Yes good job !
But unfortunately if you enable Checkboxes, the problem is still here.
then you need to remove padding for the div container of the checkbox. For example with a NodeStyle-CssClass="TreeNode"
you should try this : .TreeNode { padding-top:0px !important;padding-bottom:0px !important; }
;)
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Cheers for the good tip. Worked perfect.
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
thanks for your solution. It worked fine surprisingly. I am facing another issue by having checkboxes enabled in my treeview. When i try to expand a subnode having checkbox already enabled and having child nodes, it renders incorrectly on postback and displays in the root node level. Please reply soon with your inputs.
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Hi Vinod, eXiaMike here above already added the solution... :-)
[...]
you need to remove padding for the div container of the checkbox. For example with a NodeStyle-CssClass="TreeNode"
you should try this : .TreeNode { padding-top:0px !important;padding-bottom:0px !important; }
[...]
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Unfortunately, this didn't work for me :-(. I will try to explain my scenario with a small example. Lets say i have a tree like a<-b<-c (a is parent to b & b is parent to c). When i check the checkbox for node 'a' and then click + sign to expand, the node 'b' is displayed and added NOT as a child to node 'a' but in the same root level as node 'a' exists. Same is the case when node 'b' is checked and expanded to get node 'c'.
When i click on the node 'b' it refreshes the grid and the tree is formed correctly i.e. node 'b' child node of 'a'.
Please let me know what can be done to fix this.
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Vinod, this is a completely different problem, not really what's described in the post (I guess that's why the solution does not work for you)... the indentation level has nothing to do with the "dotted" line which is just a "cosmetic" thing.
What you describe sounds like either a coding issue (or maybe a bug in the control, it cannot be excluded at the moment) so I think you should really consider opening a call with CSS (http://support.microsoft.com) and someone from my team (maybe me, if you're based in EMEA) will have a look, best working on a sample to repro the problem.
HTH
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
This fix didn't want to work for me...
I tracked it down to may master page's style sheet setting a vertical-align: top; to the region containing the treeview. This still left gaps in the lines... to fix this I just added vertical-align: baseline; to the treeviews style & that fixed it...
This took me hours to find... hope it helps someone else.
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
The fix above sorted out my page in IE but not FF. After a bit of playing about I managed to sort it by adding the following:
.tree td img { vertical-align: bottom; }
SJ
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Worked fine in IE7, FF 2 and Opera 9.25.
Many thx to you and Markus Rheker !
/M.E.S.H
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Awesome solution to a common ASP problem!
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Thank you SOOOOOO much. Worked perfectly!
# re: Broken line in ASP.NET 2.0 TreeView in IE 7
Thank you very much for this handy research