August 2006 - Posts

I was working with my application the other day, and upon saving a page, without closing the browser, I realized that the framework detected the change immediately and automatically.  I was astonished at how that worked; I could tell it was working because you could see it was taking a lot longer to process the page, like it usually does when you first load the application.

I saw about this reading Dino Esposito's Programming Microsoft ASP.NET 2.0 Advanced Applications.  Upon compilation on the first page load, the page is compiled, which it notes the file dependencies.  Upon updating the page assembly, it is renamed with a ".delete" extension, which is OK to do and won't cause an error.  This occurs every time that the page assembly is updated, up to a maximum number of times (set in the web.config file), and then the application is restarted.
Posted by bmains | with no comments
Filed under:

For those that have applications that work with office, and unfortunately don't have Office 2003, but XP, you have the option of using the Office XP PIA's (Primary Interop Assemblies) to install on the machine for your application, so that you can use a .NET interface when working with the Office API.

To install it, you have to run the register.bat, which uses the gacutil to install them in the GAC.  You should use the Visual Studio command prompt to install, but if you don't have access to it, you can copy it to the "windows\microsoft.net\framework\<version>\" folder.  I installed them with the 1.1 version utility.

If you don't want to have to find all the DLL's to later delete, you can put them in a custom subfolder, then hack the register.bat file to include this subfolder in the registration.  Once you have these installed, you reference the Office API in the COM tab, which then instead replaces this reference with the Office .NET PIA version in the GAC, automatically for you.

Posted by bmains | with no comments
Filed under:

Recently, I had a friend who had asked me about what makes a folder or file name unique.  This project he was working on needed a unique file name, and my recommendation was the Session.SessionID used in the name would do it; of course, this was dependent on multiple files not having the same name in the session.

Recently, I've been reading ASP.NET 2.0 Advanced Topics by Dino Esposito, and the approached used by the .NET framework is to use two separate hashed folders, which determines the uniqueness of files placed in there.  If you go to c:\windows\microsoft.net\framework\<version>\temporary ASP.NET files, you will see your web projects as sub folders, followed by a series of hashed folders.

So I got to thinking that the hash approach probably would work well in determining uniqueness, as long as the hash length is sufficient.

Posted by bmains | 1 comment(s)
Filed under:
I was having a problem with template fields in a details view, where it doesn't automatically get the value from a template field.  The problem is the template shows up as a control through FindControl and a child control of the cell, whereas boundfields, etc. can be retrieved through the collection of values that are stored in the event argument.  The initial bind is OK, but like with the insert, binding isn't provided for both directions.  The problem is that the properties for those templates aren't in the collection, and aren't automatically updated, at least that is what I was having problems with.  I was getting SqlExceptions for the insert statements, stating that the value was null.  So how do you ensure that it is there, without custom inserting/updating?

The way that I did it, whether right or wrong, is to attach to the ItemInserting event.  Then, I retrieve the value from the control, and append it to the e.Values collection, which is an IOrderedDictionary.  For ItemUpdating, it is e.NewValues.  So my ItemInserting would look like:

FormView view = (FormView)sender;
DropDownList box = view.FindControl("DDL") as DropDownList;
e.Values.Add("State", box.SelectedValue);

I haven't tried this with the updating yet, but I did this with insertion, and it worked great.  I don't know if this is a good idea or not, but I don't see any other day.
Posted by bmains | 3 comment(s)
Filed under:
I was binding a link to the NavigateUrl in a repeater, and I found something funny; when I did:

NavigateUrl='item.aspx?id=<%# Eval("ID") %>'

literally renders as:

item.aspx?id=<%# Eval("ID") %>

So if you append the link inside the binding statement as such:

<%# "item.aspx?id=" + Eval("ID").ToString() %>

This will create one fluid url with the field.  Note that I call ToString() because I code with option explicit on; if you do not, this isn't needed, but is more performant if you do (but is probably negligible.
Posted by bmains | with no comments
Filed under:
The gridview and detailsview controls, which support using DataControlField classes for their columns, support the addition of any DataControlField custom fields you create.  For instance, I created a RowField custom field that is hidden, but highlights the row in the gridview row.  Below is the class I created:

public class RowField : DataControlField
{
    //Don't allow the visible property to be set
    new public bool Visible
    {
        get { return false; }
        set {  }
    }

    protected override DataControlField CreateField()
    {
        return new RowField();
    }

    public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
    {
        base.InitializeCell(cell, cellType, rowState, rowIndex);
        //Hide the cell so it isn't visible
        base.Visible = false;

        //Hook into the data binding
        if (cellType == DataControlCellType.DataCell)
            cell.DataBinding += new EventHandler(cell_DataBinding);
    }

    void cell_DataBinding(object sender, EventArgs e)
    {
        Control control = sender as Control;
        //The Row is available in data binding stage, but not initialization
        GridViewRow row = control.NamingContainer as GridViewRow;
        //Add coloring attributes
        row.Attributes.Add("onmouseover", "this.bgColor = '#C0C0C0'");
        row.Attributes.Add("onmouseout", "this.bgColor = '#FFFFFF'");
    }
}

When you inherit from it, it creates the CreateField by default, which is declared abstract/mustoverride in the base class.  This class creates a new instance of the field.  The other method I overridden was the InitializeCell class, which initializes the cell by adding controls based on the state of the row, or binding the value in the field.  I also make sure that the control isn't visible, as it doesn't hold a value.

In this instance, I wanted to add custom code to color the row whenever it was moused over, or unselect it whenever mouse out occurred.  But, to do this, you have to color the row.  The row isn't accessible until binding, not during initialization.  So I had to tap into the DataBinding event, which has access to the parent naming container (the GridViewRow), and so I could append attributes to.

This seems like overkill though; why not just tap into the itemdatabound or itemcreated event?  Well, this serves as an introduction to the class, but it will be useful for another control that I will be creating, hopefully that I will be posting about.
Posted by bmains | with no comments
Filed under: ,
Recently, I've been seeing the value of application frameworks, like the Membership and Roles frameworks.  Having the capabilities for your application, custom controls, and other objects to work together through a common API, components working together provide some business value.  For instance, in an example of mine, I created a custom Page class (named PageBase), which exposed a Security property.  This property was a complex object that had various security-based components I used in my application.

In my custom control library, I had an AdministratorPanel class, which in my application pages that use this PageBase class, whenever I use this AdministratorPanel in one of those web pages, I can access the Page property, converting it to a PageBase, and if the page class is actually my custom page, then I can make use of this security feature.  The following is the code:

if ((this.EnableViewState && !Page.IsPostBack) || !this.EnableViewState)
{
    PageBase page = this.Page as PageBase;
    if (page != null)
    {
        //Only make it visible if the user is an administrator
        this.Visible = page.Security.IsInRole("Administrators");
        ViewState[VISIBLE_VIEWSTATE] = true;
    }
}

It is important to use error handling to ensure if the developer is using your application framework.  For your own internal applications, it is fine; however, if you are developing something for public use, maybe the developer only wants to use several of your components in the framework.  That is one of the drawbacks with application frameworks, is that they can be severely coupled.  Coupling is the concept that states how well objects can work without referencing each other.  So an application framework would be a coupled application, whereas the enterprise library, which its components can be used without referencing other components, is decoupled.

Posted by bmains | with no comments

The DetailsView is a control that allows you to easily view a single record of data, as well as perform insert, update, and delete operations against it.  It's similar to the GridView, in that for each action, it has an -ing and -ed events, like ItemInserting and ItemInserted.  For Insert and Update events, a collection of items is stored in an IOrderedDictionary collection so you can get at the values that are stored in the collection.

This is nice way to access the values, which you use the name of the data field to reference it.  But recently I found out this is for columns other than the TemplateField, where you define a control to store the value.  For these values, when you are getting at the values, you must use the FindControl method of the details view to get the control reference.  Something to be aware of.

Posted by bmains | 1 comment(s)
Filed under:
IFormattable is an interface that defines a version of a ToString method that include a format, and a format provider, if necessary.  Within the method is a series of if statements, determining whether the format provide is null.  If it isn't, it gets an instance of the formatter that will do the work of formatting, and return the results provided by that custom mechanism.  IFormatProvider is responsible for instantiating and returning a custom formatter to do the work.

public string ToString(string format, IFormatProvider formatProvider)
{
    //If the format provider has been provided
    if (formatProvider != null)
    {
        //Get the custom formatter
        ICustomFormatter formatter = formatProvider.GetFormat(typeof(ICustomFormatter)) as ICustomFormatter;
        //If the formatter exists, return the custom format
        if (formatter != null)
            return formatter.Format(format, this, formatProvider);
    }

    //If we have a valid format
    if (!string.IsNullOrEmpty(format))
    {
        //If using placeholders, return a response
        if (format.Contains("{0}"))
            return string.Format(format, this.Key, this.Value);
    }

    return this.ToString();
}

In our method, as a backup, if the format has a placeholder, I use the placeholder to return a string that replaces the placeholders with values using string.Format.  Otherwise, the default ToString() method is returned.
Posted by bmains | with no comments
Filed under: ,

I had a custom control that I was using to render a series of text; however, it had a marking container on the side that you can click to mark a "verse" (the business object) in the collection of verses.  The collection that I use can be cast to IEnumerable, so I use it as a common denominator, so that I can use multiple sources later.  To start out, I have two variables:

float height = 0;
float offset = this.MarkingWidth + 4;

These to variables store the current height of the text that was last rendered (cumulative), and the offset to push the text <x> number of pixels to the right, outside of the marking area I mentioned before (think of the marking area as similar to Visual Studio .NET's breakpoint area, or the same with Visual C# Express).  Next, I iterate through the collection.  Through each iteration, I have the following code:

bool containsVerse = _manager.MarkedVerses.Contains(verse);
Color markingAreaColor = (containsVerse ? this.MarkingSelectionColor : this.MarkingColor);

string verseText = verse.ToString();
SizeF verseSize = e.Graphics.MeasureString(verseText, this.Font, (this.Width - Convert.ToInt32(offset)));
RectangleF markingArea = new RectangleF(0, height, this.MarkingWidth, verseSize.Height);

e.Graphics.FillRectangle(new SolidBrush(markingAreaColor), markingArea);
e.Graphics.DrawString(verseText, this.Font, new SolidBrush(SystemColors.ControlText), new RectangleF(offset, height, verseSize.Width, verseSize.Height));

height += verseSize.Height;

The first two lines determine the color of the marking area; if the verse is "marked", then use the selection color for the marking rectangle that will be rendered later.  Otherwise, use the default color.  Next, the size of the text is determined through MeasureString.  MeasureString calculates the size of the text, which this overload sets how wide the text can be, which is the length of the control, minus the offset for the marking area, which by default will calculate to 20.  This information is used to space the text; however, we are also using it to determine the height of the rectangle, so that the rectangle height and the text height will match, and rendering these lines vertically will be flush together.

The Graphics object handles filling the rectangle with the correct color, and drawing the string in the proper format.  When filling the rectangle, this actually paints the rectangled filled on screen, with the specifications in the previous line above it.  Drawing the string also uses coordinates, as the rectangle it is drawn in starts beyond the marking area, using the total height calculated for the MeasureString statement, and provide the finished width/height of the text.

It then appends the height to the total, so that the next line appears right below it, keeping the cumulative total.  As you can see, rendering windows applications is a lot more difficult than web-based applications.  The browser handles a lot of things for you that we developers can take for granted; the windows environment doesn't afford you that, for right reasons; it is meant to give you full control.  However, it requires a lot more coding.

Posted by bmains | with no comments
Filed under:
What about the common functionality, like Quitting?  The Manager static class has a Quit method.  When called, it invokes the OnQuitting method, to see if any class or other object still needs to use the application; for instance, if the user is still editing the form, this may cancel the close.  This uses the System.ComponentModel.CancelEventArgs to make that determination.  Upon success of quitting, the OnQuit method is called, which the Main windows application catches.  When it receives this event, it calls Application.Exit().  Here is what the Manager static class has defined:

public static void Quit()
{
    CancelEventArgs cancelArgs = new CancelEventArgs(false);
    if (OnQuitting != null)
        OnQuitting(Instance, cancelArgs);

    if (OnQuit != null && cancelArgs.Cancel == false)
        OnQuit(Instance, EventArgs.Empty);
}

Whenver anything tries to close the application, this method is called, which makes that determination.  Upon calling OnQuit, OnQuit event handler will handle closing the application.  You can use this approach to do more.  I have a SaveFile method that does this:

public static void SaveFile(EA.FileDialogEventArgs e)
{
    if (OnSaveFile != null)
        OnSaveFile(Instance, e);
}

OnSaveFile is raised, which is caught in the windows application.  On save file has all the pertinent save file information to show a dialog.  So the main application handles it, and passes this information along to the save file dialog box, which is declared in the windows form.

Upon saving a file, the path to the file is added to the file name property and returned to the save file object.

void MGR_OnSaveFile(object sender, Core.EventArguments.FileDialogEventArgs e)
{
    this.sfd.DefaultExt = e.Extension;
    this.sfd.Title = e.Title;
    this.sfd.Filter = e.Filter;
    this.sfd.InitialDirectory = e.InitialDirectory;

    this.sfd.ShowDialog();

    e.FileName = sfd.FileName;
}

Methods within a static class can easily invoke functionality within an application to do many things, such as prompting a Save File dialog box.  You can use such methods to drive the application, doing many things like this.
Posted by bmains | with no comments
Filed under:
Each of the object model items, Menu, MenuItem, Document, Toolbar, and ToolbarItem, maps directly to a UI element.  When is it created?  The win form that renders the UI attaches to the appropriate object model events, Menus_On<Event>, Documents_On<Event>, and Toolbars_On<Event>.  Remember that these collections are exposed through the Manager static class.

So a toolbar is created; then what?  The win form attaches to this event.  It will then be in charge of creating the ToolStrip, and pass over all of the properties from the Toolbar class to the Toolstrip UI element.  The event handler that I had created to handle this is this method:

void Toolbars_OnAdd(object parent, Core.EventArguments.ItemEventArgs e)
{
    if (e.Item is Toolbar)
    {
        Toolbar toolbar = e.Item as Toolbar;
        WIN.ToolStrip winToolstrip = ToolstripUtilities.GetToolStrip(ref toolbar);
        this.tsc.TopToolStripPanel.Controls.Add(winToolstrip);

        //Add the toolbar name to the visibility list
        WIN.ToolStripMenuItem winMenuItem = new WIN.ToolStripMenuItem(toolbar.Name);
        winMenuItem.Tag = toolbar;
        winMenuItem.Checked = true;
        this.cmsVisibility.Items.Add(winMenuItem);
    }

    else if (e.Item is ToolbarItem)
    {
        ToolbarItem toolbarItem = e.Item as ToolbarItem;
        Toolbar toolbar = toolbarItem.GetParent() as Toolbar;

        //Create the toolstrip item
        WIN.ToolStripItem winToolstripItem = ToolstripUtilities.GetToolStripItem(ref toolbarItem);
        //Add the toolstrip item to the toolstrip of the toolbar
        WIN.ToolStrip winToolstrip = toolbar.Tag as WIN.ToolStrip;
        winToolstrip.Items.Add(winToolstripItem);
    }
}

So, when a toolbar is created, the toolbar is added to the tool strip container in the win form.  But it has no items yet; this occurs when the toolbar item is added to the toolbar class.  Then, each button (or other item) is added to the toolbar in succession.  The UI object stores the OM object in the tag property, so that it can be referenced it later.  This is useful with the tool strip item addition, because you need to know the parent object to add the items to.

Notice the ToolstripUtilities class; this class is a helper class, which creates Toolstrip UI elements.  It creates the item, assigns the properties and such in a central location so you don't have a lot of code.  Take a look at this method for an example; it minimizes the size of the code when creating these items:

public static WIN.ToolStripButton GetToolStripButton(ref ToolbarButtonItem item)
{
    if (item == null)
        throw new ArgumentNullException("item", "The button item provided was not instantiated.");

    WIN.ToolStripButton button = new WIN.ToolStripButton();
    button.Text = item.Name;
    button.Image = item.Icon;
    button.Enabled = item.Enabled;
    button.Visible = item.Visible;
    button.Tag = item;
    item.Tag = button;
    return button;
}

So when you add an object model item, it creates the appropriate item through one of the ToolStripUtilities methods, and returns it.  The windows UI object is added to the toolbar, and there you have your interface, all rendering dynamically.  The icon for the button is an image, which for the default win app, I have the icons setup as resources.
Posted by bmains | with no comments
Filed under:
Windows applications are event-driven.  Events notify other objects of some action.  For instance, when a MenuItem wants to be clicked, it raises the OnClick event.  Anything that needs to work with the menu item can catch this event, and perform its work.  Remember I was talking about walking an event up the chain?  In using the menu item example, it wants to be clicked, so the OnClick event is fired.  What happens?

When the menu item was added to a collection, the collection attached to the item's events, through the AttachToItemEvents method:

protected virtual void AttachToItemEvents(T item)
{
    item.OnChange += new EventHandler(item_OnChange);
    item.OnClick += new ObjectEventHandler(item_OnClick);
    item.OnClose += new EventHandler(item_OnClose);
    item.OnDeselect += new EventHandler(item_OnDeselect);
    item.OnQueryClose += new System.ComponentModel.CancelEventHandler(item_OnQueryClose);
    item.OnSelect += new EventHandler(item_OnSelect);
    item.OnShow += new EventHandler(item_OnShow);
    item.OnCollectionAdd += new ItemEventHandler(item_OnCollectionAdd);
    item.OnCollectionClear += new EventHandler(item_OnCollectionClear);
    item.OnCollectionInsert += new ItemEventHandler(item_OnCollectionInsert);
    item.OnCollectionRemove += new ItemEventHandler(item_OnCollectionRemove);
}

The menu item raises the OnClick event which the collection receives.  The item_OnClick event handler catches this event, which it does:

void item_OnClick(object sender, ObjectEventArgs e)
{
    if (OnItemClick != null)
        OnItemClick(this, e);
}

The collection raises the OnItemClick event.  The item that is above the collection, the Menu object, catches the OnItemClick event of the collection class, through this method:

protected virtual void AttachToCollectionEvents<T>(ItemCollectionBase<T> collection) where T : ItemBase
{
    collection.OnAdd += new ItemEventHandler(collection_OnAdd);
    collection.OnClear += new EventHandler(collection_OnClear);
    collection.OnInsert += new ItemEventHandler(collection_OnInsert);
    collection.OnRemove += new ItemEventHandler(collection_OnRemove);

    collection.OnItemChange += new EventHandler(collection_OnItemChange);
    collection.OnItemClose += new EventHandler(collection_OnItemClose);
    collection.OnItemQueryClose += new EventHandler<System.ComponentModel.CancelEventArgs>(collection_OnItemQueryClose);
    collection.OnItemSelect += new EventHandler(collection_OnItemSelect);
    collection.OnItemShow += new EventHandler(collection_OnItemShow);
}

So the Menu item attaches to the OnItemClick event.  The item handles this event and raises the click event.

void collection_OnItemClick(object sender, ObjectEventArgs e)
{
    if (OnClick != null)
        OnClick(this, e);
}

This approach bubbles up the event to the parent, which you can attach to.  In the UI, you can attach to the Manager.Menus.OnItemClick event handler.  Whenever this fires, you handle it like this:

void Menu_OnItemClick(object sender, ObjectEventArgs e)
{
    if (e.Item is Menu) {..}
    else if (e.Item is MenuItem) {..}
}

This may not be the most eye appealing approach, but it works well.
Posted by bmains | with no comments
Filed under:
In the previous post, I talked about developing an object model, referencing the article written by Omar AL Zabir.  At the heart of it is a class I called Manager.  This class exposes all of the UI elements that the application.  To make the manager class statically available, you have to add this reference at the top.  This creates a new instance of the Manager class and makes it statically available, also including an Instance property.

private readonly static Manager _instance = new Manager();

public static Manager Instance
{
    get { return _instance; }
}

Through this instance object, you can expose UI elements and other objects statically through these definitions:

public static MenuCollection Menus
{
    get { return Instance._menus; }
}

public static ToolbarCollection Toolbars
{
    get { return Instance._toolbars; }
}

public static ToolWindowDocumentCollection ToolWindows
{
    get { return Instance._toolWindows; }
}

The Instance property returns the access to the private variables as described below:

private DocumentCollection _documents = null;
private ToolbarCollection _toolbars = null;
private ToolWindowDocumentCollection _toolWindows = null;

So, we have an Instance object made globally throughout the application, which contains our reference to the _documents, _toolbars, and _toolWindows collections.  These variables don't need to be static; however, the properties should be.

You can also define static methods as helper methods or that have some other functions.  This is one of my methods that I defined to append the base directory path to the partial path:

public static string CreatePath(string partialPath)
{
    //Make sure the partial path is provided
    if (string.IsNullOrEmpty(partialPath))
        throw new ArgumentNullException("partialPath", "The partial path is null");

    //if not starting with a backslash, add it
    if (!partialPath.StartsWith(@"\"))
        partialPath = @"\" + partialPath;

    //Return the directory
    return BaseDirectory + partialPath;
}

These are some of the ways you make objects statically available to the application.  I'll illustrate uses of them soon.
Posted by bmains | with no comments
A while ago, I came across an article called Implementing a Word-Like Object Model for your .NET Framework Application, by Omar AL Zabir.  I was very intrigued; this was a great way to create an object model.  However, I wanted to create something more than that.  I wanted to create something where I could dynamically generate items, instead of an API object in the object model directly relating to a UI element, such as what CAB is meant to do.

CAB is great if you are implement one or several modularized solutions, all within the same application framework; however, I'm using the object model because I want others to be able to create plugins to extend the application by adding additional menus/toolbars/ and other UI elements.

To do this, you have certain UI elements in the form shell of the application.  This application I am describing is using CAB, but only for a minimal number of elements at the current moment.  I have a form setup with the following elements:

ToolStripContainer for the layout, with only the top and bottom tool strips enabled.  In the top tool strip, I have a MenuStrip, to add menus and menu items (as talked about in that article), and I can add toolbars to this top container dynamically.  The bottom has a status panel not currently utilized yet.

Each series of items has a hierarchy, as such:

Manager (root item)
    ToolbarCollection
       Toolbar
          ToolbarItemCollection
             ToolbarItem

The object model is event-driven, in that whenever an event happens for a toolbar item, such as a click or change event, propogates up the object chain.  The ToolbarCollection is exposed through the Manager as a Toolbars property.  Because the Manager root is a static object, available through the entire application, and that the Manager class exposes the Toolbars property statically, any class in the application can tie into its events.

To elaborate further, when a ToolbarItem raises its OnClick event, the ToolbarItemCollection handles this event.  It then raises an equivalent event, called OnItemClick event, which then propogates to the Toolbar method that handles the OnItemClick event, which then raises the Toolbar's OnClick event.  The ToolbarCollection catches the Toolbar's OnClick event in an event handler, which then raises its OnItemClick event.

Any class that wants to tap into this event can attach to the OnItemClick event of the Toolbars class, such as:

Manager.Toolbars.OnItemClick += new EventHandler(Toolbars_OnItemClick);

Remember that Manager is a static class, and Toolbars is a static property.  This is the case for the exposure to Menus and Documents.  In the article above, I didn't implement Tabs; instead, I implement Documents directly.  I didn't feel the need to implement both Tabs and Documents, to make it more easy.
Posted by bmains | with no comments
Filed under:
More Posts Next page »
The leading UI suite for ASP.NET - Telerik radControls
Outstanding performance. Full ASP.NET AJAX support. Nearly codeless development.