Failed to map the path '/App_GlobalResources/'

by Arnold 19. November 2008 01:13

The scenario: I’ve been using Visual Web Developer 2008 for a web application and after I moved the application from the inbuilt ASP.NET Development Server to IIS I encountered the following exception message:

Failed to map the path '/App_GlobalResources/'


There are a few blog posts out there which may apply to your case, especially if you have Crystal Reports 8 installed. Worth mentioning is: www.thejoyofcode.com. If your situation is proior to Visual Studio 2008 you might find your solution immediately in the blog content, but if the concern is a bit newer reading through each comment might be helpfull.

Almost certainly there is a permission issue if you encountered this exception! The solution that fitted my problem is the following!

HKEY_CLASSES_ROOT\Interface\{70B51430-B6CA-11D0-B9B9-00A0C922E750} needs full permission for the ASP.NET user account! The permissions for registry keys can be set from the “Edit/Permissions…” menu point.

You also need to add permissions to the c:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA folder. If you can’t find the Application Data in All Users don’t get scared, because it’s a hidden folder. You can set your explorer to show hidden files from Tools –> Folder Options under Hidden files and folders –> Show hidden files and folders.

Hope this helps!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

ASP.NET | Programming

LINQ Method cannot be translated into a store expression.

by Arnold 17. November 2008 22:46

LINQ to Entities does not recognize the method 'Int32 ToInt32(System.String)' method, and this method cannot be translated into a store expression.


This is a shortcomming of LINQ to Entities, and indeed the ADO.NET Entity Framework at the current release! The reason for a similar exception message is that in queries on the Entity Framework, custom methods and extensions methods cannot be translated into store expressions.

There are workarounds to still enjoy LINQ to Entities and as an example please read the following:

My example uses the AdventureWorksDB database which can be downloaded from http://www.codeplex.com. I’ve generated the Entity Data Model from the database (in case you wish to replicate this behavior). The scenario is the following: I have a TextBox and a Button on a form and I want to print the name of the Contact by entering the ContactID into the TextBox.

<div>
    <asp:Label ID="lblContactID" runat="server" 
AssociatedControlID="txtContactID">ContactID:</asp:Label> <asp:TextBox ID="txtContactID" runat="server"></asp:TextBox> <asp:Button ID="btn" runat="server" Text="Search" OnClick="btn_Click" /> <br /> <asp:Label ID="lblContactName" runat="server"></asp:Label> </div>

The obvious thing to do is to apply a Where clause on an EntityCollection and filtering everything on the ContactID given in the txtContactID TextBox. If you use Convert.ToInt32(“ID”) in the Where clause the upper Exception is thrown.

protected void btn_Click(object sender, EventArgs e)
{
    AdventureWorksEntities entities = new AdventureWorksEntities();        
    Contact contact = entities.Contact
            .Where(c => c.ContactID == Convert.ToInt32(txtContactID.Text)).FirstOrDefault();
    if (contact != null)
        lblContactName.Text = contact.FirstName + " " + contact.LastName;
    else lblContactName.Text = "Contact not found!";
}

The workaround to this is to declare a variable of type int, which contains the converted value from the TextBox and use this variable in the Where query.

protected void btn_Click(object sender, EventArgs e)
{
    AdventureWorksEntities entities = new AdventureWorksEntities();
    int ContactID = Convert.ToInt32(txtContactID.Text);
    Contact contact = entities.Contact
                     .Where(c => c.ContactID == ContactID).FirstOrDefault();
    if (contact != null)
        lblContactName.Text = contact.FirstName + " " + contact.LastName;
    else lblContactName.Text = "Contact not found!";
}

Because this feature is available in normal LINQ to SQL I hope the ADO.NET team will do some improvement on this in the next major release of the Entity Framework.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

LINQ | C# | ASP.NET | Programming

ModalPopupExtender in a GridView sample

by Arnold 11. November 2008 18:49

Although the ModalPopulExtender isn’t new at all there are still countless poeple who search the web for a comprehensive sample on how a ModalPopupExtender is used from a GridView.

First of all you’ld need to have a Button in each row which should trigger the ModalPopupExtender, then you would need to have an instance of a ModalPopupExtender with the TargetControlID set to the ID of that Button.

On the page you should create a Panel which the one which should popup whenever you press the button inside the GridView. This is the preeliminary setup. Because you don’t just pop up a modal “Window” on your form for fun … you need controls to interact with the user! For example one which should Cancel the operation and the other one which should proceed the operation. These can be using the OkControlID and the CancelControlID of the ModalPopopExtender.

This again is all fine … buuuuut without any postback there is no fun … what would be the real reason to use such a scenario where you don’t “save” the user’s choice. There has to be some functionality which sends the form back for processing.

Things that you need to consider in a sitation like this:

  1. The Cancel control simply hides the form (maybe you would need to clear the form before you let it pop up again!). Mind you, there is another way to do this using Javascript by setting the OnCancelScript property of the ModalPopupExtender.
  2. The OK control simply hides the form, which is not very good if you want to validate a field for example (and you still need to have the Modal Panel open if it didn’t pass the validation). Once again this can be done using the OnOkScript property of the ModalPopupExtender, but as more people are confortable with server-side validation than with client-side validation I’'ll show a way to leave the modal popup open even after a postback.
  3. The Control that triggers the opening of the ModalPopupExtender often needs a postback aswell to set up the Controls in the Modal Panel. (Ex: To load the firstname, lastname for which you wish to update the birthday details).

This example exposes a solution to all of the above points! To exemplify this I came up with a little scenario, you have a list of products which you can add to your cart! The GridView contains a button for each product, and by pressing it a Modal Popup comes up where you can fill in the Quantity you wish to order! Of course the modal popup contains the add button which acts as the “OKControlID” and a cancel button which is the Cancel Control ID. The OKControlID isn’t explicitely set because it would automatically hide the ModalPopup, so the actuall showing and hiding is done on the codebehind.

<asp:GridView ID="gv" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID"
    DataSourceID="EntityDataSource1">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:ImageButton ID="btnSelect" runat="server"
                                 ImageUrl="~/Images/addtocart.gif"
                                 ImageAlign="AbsMiddle" OnClick="btnSelect_Click" />
                <ajax:ModalPopupExtender ID="gv_ModalPopupExtender" runat="server"
                                         TargetControlID="btnSelect"
                                         PopupControlID="pnlModalPanel"
                                         CancelControlID="btnCancel"
                                         BackgroundCssClass="modalBackground">
                </ajax:ModalPopupExtender>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="ProductID" HeaderText="ID"
                        ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
                        SortExpression="ProductName" />
        <asp:BoundField DataField="ProductPrice" HeaderText="ProductPrice"
                        SortExpression="ProductPrice" DataFormatString="{0:C}" />
    </Columns>
</asp:GridView>

* Notice how each row in the GridView (except of course the header and the footer) contains an ImageButton and a ModalPopupExtender.

For a visually pleasing result the BackgroundCssClass of the ModalPopupExtender is set. You could use the following style for a start:

<style type="text/css">
    .modalBackground
    {
        background-color: Black;
        filter: alpha(opacity=80);
        opacity: 0.8;
        z-index: 10000;
    }
</style>

The panel that will pop up can be inserted into an UpdatePanel so that when there is an async postback so people can’t notice the whole page bouncing back and forth. I’ve put the pnlModalPanel inside an UpdatePanel because the btnAddtoCart button needs to do some logic on the codebehind.

<asp:Panel ID="pnlModalPanel" runat="server" Style="display: none;">
    <table>
        <tr align="center">
            <td colspan="2">
                <asp:Label ID="lblQuantity" runat="server" 
                           ForeColor="White">Quantity:</asp:Label>
                <asp:TextBox ID="txtQuantity" runat="server"></asp:TextBox>
            </td>
        </tr>
        <tr>
            <td align="left">
                <asp:Button ID="btnAddToCart" runat="server" 
                            Text="Add to Cart" OnClick="btnAddToCart_Click" />
            </td>
            <td align="right">
                <asp:Button ID="btnCancel" runat="server" Text="Cancel" />
            </td>
        </tr>
    </table>
</asp:Panel>

The first noticeable thing that happens on codebehind is that I set the OnClientClick attribute of the btnAddToCart button, so that it will post back.

protected void Page_Load(object sender, EventArgs e)
{
    btnAddToCart.OnClientClick = String.Format("functionPostback('{0}','{1}')",
                                                     btnAddToCart.UniqueID, "");
}

Because I manually want to show the modal popup (this might be due to the fact that the controls inside the popup have to initialized according to the pressed button or row). This is not available in my example but maybe it would be good to load the product name and price inside the modal popup so we can insert the correct quantity accoring to our budget. This is why I’m showing the modal popup from server side. In my example I’m only clearing the quantity textbox.

protected void btnSelect_Click(object sender, ImageClickEventArgs e)
{
    GridViewRow row = ((GridViewRow)((ImageButton)sender).NamingContainer);
    //NamingContainer return the container that the control sits in
    AjaxControlToolkit.ModalPopupExtender mpe = 
                       (AjaxControlToolkit.ModalPopupExtender)row.FindControl("mpe");    
    txtQuantity.Text = ""; //reset the quantity textbox
    mpe.Show(); //show the modal popup extender
}

The next thing to do is to handle the logic of the btnAddtoCart button where for the sake of the example I’m only setting a label to the quantity that has been selected!

protected void btnAddToCart_Click(object sender, EventArgs e)
{
    lblMessage.Text = txtQuantity.Text + " items have been added!";
    txtQuantity.Text = ""; //reset the quantity textbox
}

A tricky situation for the btnAddToCart_Click function is when the user would like more products than what the you can deliver (not enough products in stock, etc). In that case you would need to set a label inside the ModalPanel to a message telling the customer that there is a certain problem. The important thing is that after the postback ends the ModalPopup needs to be shown again. You need to find the instance of the ModalPopupExtender that has been shown in the first place and then call the Show() method on it.

Working with the ModalPopupExtender in more complex situations can be quite tricky but the yielded result can be ever more satisfactory if you get it right.
If you need any assistance don’t hesitate to write me and together we could find a solution, and if you liked this post don’t forget to kick it!

Currently rated 4.0 by 2 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

AJAX | ASP.NET | C#

LINQ to XML - XPath

by Arnold 9. November 2008 20:48

LINQ to SQL may be dying these days, and to be frank that’s not a big deal as the Entity Framework is out which will 100% replace it. But LINQ as a concept is something new and won’t be out for some time!

While doing some configuration work I got into a sitation where I needed to query an XML file. Immediately my thoughts went to LINQ, and in term LINQ to XML. It is a great addition to the LINQ family but in terms of readability it’s far cry away from the old days when XPath was in use.

After a short search I noticed that the System.Xml.XPath namespace contains exactly what I need: LINQ to XML Extension methods. The 3 additional methods are: XPathEvaluate() which returns an object type, XPathSelectElement() which returns an XElement type and XPathSelectElemens() wich returns IEnumerable<XElement>.

Reading the documentation of this Extension class on MSDN lets us know the following: “There is some performance penalty for using these methods. Using LINQ to XML queries yields better performance.” So it is only advisable to use such LINQ to XML with XPath queries if and only if your application won’t suffer from the slight loss of performance!

The reason why I’m willing to allow such a performance loss in my application is the maintenability factor. Normally the maintenance cycle of an application is many times longer than the development cycle. This is why we always need to take care about how well our code is written! A clear query in a succinct syntax is ever easier to read, thus easier to maintain than a very long expression with many “calls” chained together

As a short demonstration of the idea please consider reading the following example:
Consider the following XML file!

<Clients>
   <Client>
     <CompanyName>Name 1</CompanyName>
         <ContactPerson>
             <FirstName>Firstname 1</FirstName>
             <LastName>Lastname 1</LastName>
             <Phone>Phone 1</Phone>
         </ContactPerson>
   </Client>
   <Client>
     <CompanyName>Name 2</CompanyName>
         <ContactPerson>
             <FirstName>Firstname 2</FirstName>
             <LastName>Lastname 2</LastName>
             <Phone>Phone 2</Phone>
         </ContactPerson>
   </Client>
</Clients>

In order to receive the phone number of the Contact Person whose FirstName is “FirstName 2” using LINQ to SQL you’ld need to use something similar to:

from xElem in xDoc.Descendants("Clients").Descendants("Client").Descendants("ContactPerson")
where xElem.Element("FirstName").Value == "Firstname 2"
select new { PhoneNumber = xElem.Element("Phone").Value };

But by using XPath we could simplify this allot. Only one line is sufficient to execute the query, and it is extremely clear which elements we parse and what we query for! Of course this sample will throw an exception if there is no contact person whose Firstname is “Firstname 2”. It will generate an InvalidOperationException due to the First() call with the following exception message: “Sequence contains no elements”. Please consider reading my post about this Exception if you are interested in how to avoid it!

xDoc.XPathSelectElements("//Clients/Client/ContactPerson[FirstName='Firstname 2']")
.First().Element("Phone").Value;

An extensive XPath Syntax reference can be found on www.w3schools.com. Once again, if performance is not an issue in your application consider using XPath as it’s much more “visible”, much more clear thus much easier to maintain than a regual LINQ to XML query.

LINQ to XML for XPath reference is also available on MSDN.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

C# | LINQ | Programming

LINQ: OrderBy on multiple Fields

by Arnold 2. November 2008 22:52

Most people think that by calling OrderBy().OrderBy() will solves the problem of ordering a sequence by multiple fields. Well I'm dissapointed to announce this is not true because the second call overwrites the ordering clause specified in the first one!

First of all lets analyze the architecture of a LINQ ObjectQuery. The important peice is what it actually returns, namely: an IQueriable object! This IQueriable interface implements the IEnumarble interface which we are normally used to use when creating an ObjectQuery.

//sample ObjectQuery
IEnumerable<TimeSheets> timesheets = entities.TimeSheets
     .Where(mts => mts.aspnet_Users.UserId == UserId).ToList()
     .Where(mts => mts.TimeStamp.Value.Date.Month == Month)
     .Where(mts => mts.TimeStamp.Value.Date.Year == Year);

But because I normally use the IEnumerable interface as the expected outcome of an ObjectQuery I got a bit sidetracked when I needed to OrderBy() on multiple Fields. 

//sample ObjectQuery with OrderBy clause (only one field)
IEnumerable<TimeSheets> timesheets = entities.TimeSheets
     .Where(mts => mts.aspnet_Users.UserId == UserId).ToList()
     .Where(mts => mts.TimeStamp.Value.Date.Month == Month)
     .Where(mts => mts.TimeStamp.Value.Date.Year == Year);
     .OrderBy(mts => mts.TimeStamp); 

The fact of the matter is that OrderBy() returns an IOrderedEnumerable which then exposes the Methods: ThenBy() and ThenByDescending(). This means that we can OrderBy on multiple Fields by chaining the OrderBy() and ThenBy() together.

Here's a little example of where this comes in handy. In my example I need to return all the TimeSheet entries of a User for a specific Month and a Year then I need to order all elements by the date the entry was introduced on and by the TaskID that the time sheet entries refer to.

/// <summary>
/// Returns all recorded time sheet entries for a Membership User (UserID), Month and Year
/// </summary>
/// <param name="UserId">The UserID of the Membership User</param>
/// <param name="Month">The specific Month for the timesheets</param>
/// <param name="Year">The specific Year for the timesheets</param>
/// <returns>IEnumerable<TimeSheets> - the List of 
/// Timesheets for a Membership User (UserID), Month and Year</returns>
public static IEnumerable<TimeSheets> TimeSheetsOf(Guid UserId, int Month, int Year)
{
     EDMEntities entities = new EDMEntities();
     IEnumerable<TimeSheets> timesheets = entities.TimeSheets
        .Where(mts => mts.aspnet_Users.UserId == UserId).ToList()
        .Where(mts => mts.TimeStamp.Value.Date.Month == Month)
        .Where(mts => mts.TimeStamp.Value.Date.Year == Year);
     foreach (TimeSheets ts in timesheets)
        if (!ts.ProjectTasksReference.IsLoaded) ts.ProjectTasksReference.Load();
     return timesheets.OrderBy(mts => mts.TimeStamp)
                      .ThenBy(mts => mts.ProjectTasks.TaskID);
}

* Note that the we need to use the .ToList() call because we cannot use .Date.Year in LINQ to Entities, or else the following:  System.NotSupportedException will be thrown: The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

ADO.NET | C# | LINQ | Programming

LINQ: Sequence contains no elements

by Arnold 28. October 2008 20:26

The InvalidOperationException: Sequence contains no elements exception is thrown whenever you try to retreive an element from an empty sequence. This generally happens when you call First on an empty sequence. What I think about for this situation is that I'ld need a method which would return null if the sequence is empty and the first object (maybe the only object) in the sequence otherwise.

In this case the call of FirstOrDefault is recomended. Although after a few searches I've found something similar: we could Single or SingleOrDefault instead of First. Calling these methods is almost exactly what First does except ... this will generate another exception if the sequest contains more elements: InvalidOperationException: Sequence contains more than one element. But the convenient factor is that it quietly returns the single element in a sequence, null of the sequence is empty and the above mentioned InvalidOperationException: Sequence contains more than one element.

This is all fine until you are into ADO.NET Entity Framework like me recently. Because you are used to working by using .Single() and .SingleOrDefault() you think it's the same procedure while querying an entity data model. And you won't be pleased to see the following exception: NotSupportedException: The method 'Single' is not supported by LINQ to Entities. Consider using the method 'First' instead.

A solution to the unsuported call of Single on LINQ to Entities is the following. The query can be transformed to LINQ to Objects by calling ToList or ToArray, and because LINQ to Objects supports the Single Method, we can now call Single on the returned IEnumerable<TSource> type (Ex: .ToList().Single()). Like this we can still enjoy the ADO.NET Entity Framework and also use the Single method.

Any other ideas or solutions are welcome!

Currently rated 4.0 by 3 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , , ,

.NET 3.5 SP1 | ADO.NET | LINQ

What's hot in ASP.NET 3.5 SP1

by Arnold 22. October 2008 19:16

First of all it's worth mentioning that Microsoft brought enhancements to the ASP.NET AJAX Extensions. Now we can use a History control which allows us to use the back button to navigate back to a state before the last async postback happened.

Then there is Dynamic Data which is a framework that discoveres the data model and determines the UI which is best suited, dynamically, during runtime. This sounds weird but it can be of big help! Ex: When you try to display a DateTime value in a GridView, you can use a <asp:DynamicField ... /> which will automatically print your DateTime value nicely formatted. To achieve this with the Normal <asp:BoundField ... /> you needed to set HtmlEncode="false" and DataFormatString="{0:D}". If your DataField is a simple string, this will render a LiteralControl. Not only do these work in Read-Only mode, this also happens in Edit mode which can big of big help.

For those who are bored with HttpContext.RewritePath(), and for those who are tired of using the regular expression based configuration of most URLRewriting modules ... there is good news for you! ASP.NET 3.5 SP1 introduces: URL Routing. In URL routing, you define URL patterns that contain placeholders for values that are used when you handle URL requests. At run time, the pieces of the URL that follow the application name are parsed into discrete values, based on a URL pattern that you have defined.

But now ... the piece de la resistance ...
Ladies and Gentleman, would you please welcome the new ADO.NET Data Platform.
One thing was desperately missing from ADO.NET. Working directly against a Relational Storage Schema (in english: the Typed DataSets) is fun, but it can be very difficult to maintain. Once a database schema changes a little bit, chances are that the change on the application part will be substantial, and once again, very difficult to maintain!
As a solution this sounds probably familiar to those who have heard about ORM. But for all those who didn't have anything in common with ORM, well here's a short intro!
ORM - Object Relation Mapping, The problem is that data in the database is very difficult and time consuming to present to the application in a logic manner! The aim is to create a virtual object database, each object representing a relation in your database tables! Ex: a row in the table Customer would correspond to an object Customer in your application; in the same way the tables: Order and OrderProducts; an object Order which contains a List<OrderProducts> would model this situation well!

There are a bunch of products available on the market some free others not, but to get an idea here are some examples: NHibernate, LLBLGen Pro, EntitySpaces, OPF.NET, etc.

Now, to ADO.NET Entity Framework, a part of the ADO.NET Data Platform. It generates the underlying conceptual object model from a database, which you can program against. This way you have access to data from an Object level! Why this is good? It scales well, it's easy to maintain, and most importantly it's very quick to program against.
Microsoft also provides LINQ to Entities. If anybody has used LINQ queries agains simple collections, well you can use LINQ to query Entities:

                EDMEntities entities = new EDMEntities();
                IQueryable<Companies> query = from c in entities.Companies
                                              where c.aspnet_Users.UserId == UserId
                                              select c;                            
                //query.Count() now contains the number of Companies owned by a User   

The .NET Framework 3.5 SP1 brings allot of nice enhancement, and gladly not only for the web developer!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

ASP.NET | Programming | .NET 3.5 SP1 | ADO.NET

ValidationSummary displayed multiple times in UpdatePanel

by Arnold 14. October 2008 18:18

Restricting the user from leaving certain fields blank is often mandatory, because we don't want to have empty fields in our database, or we may want the user to specify exactly how many products he wishes to order. Asp.net comes in really good here with the Validation Controls. For my example the RequiredFieldValidator is perfectly suited because it displays a little error message for the control it validates.

All is fine until you have 40-50 fields that have to be filled out. In this case it's of good practice to use the ValidatioSummary control which summarises all the error messages from the ValidationGroup and shows them either in text on the page or as a Javascript alert(). 

All is fine again until you use the ValidationSummary inside an UpdatePanel, where something rather interesting happens. The alert box is displayed multiple times. When I got this behaviour it was even more interesting that the number of times the alert box is displayed was not constant. Many readers will immediately tell me that Microsoft admits that Validation Controls don't work well with the Asp.net AJAX UpdatePanel. Furthermore other readers will tell me that there is a certain validators.dll out there, and by defining some TagMappings in the web.config file all UpdatePanel Validation controversies will be solved. And yes sir, this is all true, but this still won't solve the ValidationSummary multiple alert() situation in the UpdatePanel.

Later I've noticed that there is a correlation between the number of times the alert is displayed and the number of asynchronous postbacks in that UpdatePanel. Yes, the ValidationSummary alert() is displayed exactly the number of asychronous postbacks times plus one. (0 postbacks --> 1 alert, 2 postbacks ---> 3 alerts)

To avoid this behaviour you only have to place the ValidationSummary outside the UpdatePanel, this will prevent it from reregistering itself for validation on each asynchronous postback.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

AJAX | ASP.NET | Programming

Styling a TreeNode with CssClass

by Arnold 9. October 2008 21:27

Web development with Asp.net is very fast. We have drag and drop controls with out of the box functionality. This concept of prebuild controls is of huge advantage when it comes to rapid application development, saving us allot of time ... but there is one major drawback. We are normally limited to what the controls offer in: rendering, functionality, etc.

Microsoft controls normally render table based designs, which are very difficult to style. If you want to override this you can achieve it using CssFriendlyControlAdapters. It's the same case for the TreeView Control but the table based rendering is probably not the thing that bothers me the most!

In my opinion Microsoft did a poor job with the TreeView control when talking about style. Normally Asp.net controls have Style and CssClass properties to set visual appearance. It is not the case for a TreeNode.
I know there is a way to style a TreeNode, but only on a general level like: NodeStyle, LeafNodeStyle, HoverNodeStyle, RootNodeStyle. I wish there was a bit more flexibility. Styling a TreeNode individually is totally essential as we may want to adjust color based on some values.

There an event called TreeNodePopulate which can be handled to insert some custom code in order to achieve styling.

    protected void tv_TreeNodePopulate(object sender, TreeNodeEventArgs e)
    {
        if (e.Node.Value == "something you expect")
        {
            e.Node.Text = "<div style='color:blue'>" + e.Node.Text + "</div>";
        }        
    } 
The only problem here is that this event is only fired when we are databinding the TreeView. In practice we normally create our TreeView dynamically using the Nodes/ChildNodes.Add() properites.

The obvious solution in this case is to extend the TreeNode class, add a property called CssClass which will be rendered accordingly. Due to the stateless nature of the web, settings like our CssClass string have to be saved somewhere. The usual place to save such information is the ViewState. Sadly the ViewState object isn't accesible from the TreeNode class, therefore we need to override the LoadViewState and SaveViewState methods.

Here's the CustomTreeNode class which lets us set the CssClass individually.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
/// <summary>
/// This is an extended TreeNode, to allow styling
/// </summary>
public class CustomTreeNode : System.Web.UI.WebControls.TreeNode
{
    public CustomTreeNode()
        : base()
    {
    }
    public CustomTreeNode(string Text)
        : base(Text)
    {
    }
    private string _CssClass = null;
    public string CssClass
    {
        get
        {
            if (_CssClass != null)
                return _CssClass;
            else
                return String.Empty;
        }
        set
        { _CssClass = value; }
    }
    protected override void LoadViewState(Object savedState)
    {
        if (savedState != null)
        {
            object[] myState = (object[])savedState;
            if (myState[0] != null)
                base.LoadViewState(myState[0]);
            if (myState[1] != null)
                CssClass = (String)myState[1];
        }
    }
    protected override Object SaveViewState()
    {
        object baseState = base.SaveViewState();
        object[] allStates = new object[3];
        allStates[0] = baseState;
        allStates[1] = CssClass;
        return allStates;
    }
    protected override void RenderPreText(HtmlTextWriter writer)
    {
        writer.AddAttribute("class", CssClass);
        base.RenderPreText(writer);
    }
}

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , , , ,

ASP.NET | C# | Programming

Colorful parallelism

by Arnold 7. October 2008 19:01

I thought of rail lines as two infinitely parallel lines, that they don't ever intersect. And still when looking at this digital photo it's somehow a paradox.
My maths teacher told us that two parallel lines meet in infinity.

Colorful parallelism - optical illusion

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

Photography

© 2007-2008 DreamLab Solutions

About the author

My name is Arnold Matusz. I'm a romanian web developer with a passion for photography and cars.

Calendar

<<  November 2008  >>
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

View posts in large calendar