July 2006 - Posts

In breaking up my discussion on CAB, I have been reading about a lot of the newer technologies that will be a part of Windows Vista, such as Atlas and Windows Communication Framework (WCF) and its use of XAML, which are really neat technologies.  However, with all of the new software frameworks that come out from Microsoft as well, and with the advent of a new framework (hopefully only 2.0 plus Atlas and WCF, plus other Vista components), and with XAML's new learning curve, you have to wonder if all of this rush will ever slow down.

It wasn't too long ago that the 2.0 framework was released, and now I see that the 3.0 is coming out... the 2.0 doesn't even have all the post release bugs worked out of it yet!  Not to mention all the future complications it can add.  I understand the push for new technology, but so far, every move to a new version means purchasing a new set of tools, which can get quite expensive.  I hope the move to Vista still at least allows Visual Studio 2005 to work with it.

My wife, when she was working as a teacher, said that I wouldn't believe all the work she had to do to stay ahead.  I understood her, as she always had papers to grade while at home.  But I don't think she realized that it is the same for me, as to stay ahead, it really requires an effort on and off the work place.  Talk about the potential for a major burnout.

I just wish I knew if this push is going to slow down at some point.  A new framework every two years is going to get old after a while.

Posted by bmains | with no comments
Filed under:
Error handling in a CAB application can be tricky.  Because the ModuleLoaderService loads the CAB application, if there is an error that isn't handled in the application, the ModuleLoaderService throws an error, effectively hiding the true error in the application.  Because of this, debugging is a more complicated process, as you have to run through more amounts of code to find the problem.

Naturally, developers have assumptions though; we know our code usually pretty good, and have ideas about what was changed from the last time when it did work.  Though, this assumes that the problem is from our own code, though in multi-developer projects, the true error may be harder to find.

As such, this relies on the importance of using Debug.Assert statements in your code.  If it detects a problem with a value, it notifies you with the message you provided, stating where the problem was found.  This is a way, when debugging, to find things not normally found.  It is an essential in the war against errors, especially in complex applications.
In the Composite UI Application Block, the windows application that is the host uses a class to run the project.  In C#, this is the default setup for a windows application; it includes a Program.cs file that runs the default form.  This is a great setup for CAB, because you need to change the implementation to this:

public class Program : FormShellApplication<WorkItem, MainForm>
{
   
}

This shell represents a windows forms shell that you created with your windows forms project, that the CAB project represents.  The WorkItem first parameter in the generic parameter list is the root type of object to implement, which  means we want to implement any class that inherits from WorkItem.  The second is the type of shell form to implement.  In our class, we have a static definition of:

[STAThread]
static void Main()
{
    Program program = new Program();
    program.Run();
}

The run method handles the initialization and preprations of the CAB objects in the block.  The list of services available after instantiation (as provided by the documentation) is:
  • SimpleWorkItemActivationService
  • FileCatalogModuleEnumerator
  • WindowsPrincipalAuthenticationService
  • ModuleLoaderService
  • DataProtectionCryptographyService
  • TraceSourceCatalogService
  • CommandAdapterMapService
  • WorkItemExtensionService
  • WorkItemTypeCatalogService
  • ControlActivationService
That is a lot of services!  In the FormShellApplication class, we have methods we can override, one of the more common of which is this:

protected override void AfterShellCreated()
{
    base.AfterShellCreated();
}

This method fires after the shell is created (as the name gives away), which you can do additional things, like work with these services after the shell is created and setup.  More commonly, this method will register UI extention sites, which registers certain UI elements so that you can use a command name to interact with it, instead of interacting with the object itself (more on this later).

Another handy method is the OnUnhandledException method, which receives unhandled exceptions, and allows you handle them in some way, by notifying the user, or writing an event, such as this declaration:

public override void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    base.OnUnhandledException(sender, e);

    Exception ex = e.ExceptionObject as Exception;
    string message = string.Empty;
    string title = "Error";

    if (ex != null)
    {
        message = ex.ToString();
        EventLog log = new EventLog("Application");
        log.Source = "MyApp";
        log.WriteEntry(message, EventLogEntryType.Error);

        MessageBox.Show(message, title);
        Application.Exit();
    }
}
The Composite UI Application Block is a new application block (well, not so new; CTP in december) that makes it easier to develop windows applications.  It creates separate loadable modules that are dynamically ran in the application, working with a new object called the WorkItem.  The WorkItem is basically a class that can be considered a unit of work.  It can handle whatever you want to do, such as setting up the user interface, retrieving data from the database, or whatever else you want to do.

Specifically, in one of my C# solutions, I have two projects:

MainApp - compiles in MainApp\bin\Debug - Main project
CABApp - compiles in ..\MainApp\bin\Debug - Separate project to do whatever

The reason you redirect the CAB application to compile in the MainApp's bin folder is because CAB dynamically loads the CABApp module.  It knows this because it looks for a ProfileCatalog.xml file in the MainApp folder, which has this declaration:

<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile" >
    <Modules>
        <ModuleInfo AssemblyFile="CABApp.dll" />
    </Modules>
</SolutionProfile>

A word of advice: make sure that the ProfileCatalog.xml has a Copy to Output setting of Copy Always or Copy If Newer, so it is available at runtime.  When the MainApp runs, the CAB Application loads a custom module that Inherits from ModuleInit.  So in our CABApp project, we need a CABModuleInit class that does this:

public class CABModuleInit : ModuleInit
{
    private WorkItem _workItem = null;

    [ServiceDependency()]
    public WorkItem WorkItem
    {
       get { return _workItem; }
       set { _workItem = value; }
    }

    public override void Load()
    {
       CABWorkItem workItem = this.WorkItem.WorkItems.AddNew<CABWorkItem>();
        workItem.Activate();
    }
}

It is responsible for loading the custom work item into the work items collection and activating it.  Note the [ServiceDependency()] attribute, which is a new feature called Inversion of Control, or IoC.  You can read more about IoC here.  I won't go into specifics here, but basically, dynamically at runtime, an instance to the work item is provided to the setter of the property.  With CAB, you will see this application design approach throughout.  Continuing on, our custom work item looks like this:

public class CABWorkItem : WorkItem
{
    protected override void OnActivated()
    {
       //Do whatever, load custom API items, load data, etc.
    }
}

Basically the work item is a unit of work.  It is tasked to do whatever you need it to do.  There are other benefits, but this is the basics to building a custom CAB module.  I'll be talking more about CAB in future posts.  In my applications, I use these modules to interact with an application object model I created for my application.

Typically, the CAB application has a group of user interfaces and UI code to interact with the main form.  In my application, I use an object model to load the UI elements and objects into the API, which loads it into the application, all initially setup from the work item.  But you can use it to do whatever you need to do.

I was looking with Reflector at the GridView control the other day, realizing how it received click events for the buttons defined in the GridView.  Whenever a button is clicked, it has a command associated with it.  This command event argument is bubbled up to the GridView, which is handled by a private method.  This method determines which event needs to be raised and which code needs processed, such as the editing, updating, or cancelling events.  This occurs with each control handling bubbling, as such:

protected override bool OnBubbleEvent(object source, EventArgs args)
{
   if (args is CommandEventArgs)
   {
      base.RaseBubbleEvent(source, args);
      return true;
   }

   return false;
}

The returned value determines whether to keep raising the bubble event.  Each time it is called, it is handled by the protected OnBubbleEvent method, which you can keep the bubbling process going, call another appropriate event, or cancel it.

In the parent composite data-bound control, you return false as to not continue raising the event; however, based on the command value, you can perform a specific action.  For example, when the Edit button is clicked in the GridView, a command event argument for the linkbutton clicked (with the command name set to "Edit") is bubbled up the chain until it gets to the GridView, which handles the Edit event.  This goes the same for all events.

Posted by bmains | with no comments
Filed under: ,

I must admit some initial flaws in my control design.  I originally thought that the custom control could work by having the child control that is repeated could build its own control collection and manage its own viewstate.  I think I was wrong, and I noticed several problems with my design.

The first problem I noticed is how it posted back the events to the composite data bound control.  There were three events in the child control that responded to button clicks.  Whenever the button click raised the appropriate event, which was handled by the parent control, viewstate had not been loaded for the child control, so the original values for the text and title fields were not loaded.

I played around when the events were called, even writing code to load them in the prerender event, which worked, but then the new values for the newly entered item weren't available, or I was having other problems...  Essentially, I couldn't get it, as a composite control, to work with loading the control properties, no matter whether I used server-side postbacks for the linkbuttons, or use the OnClientClick property to use the IPostBackEventHandler.

The problem with IPostBackEventHandler, was when the CreateChildControls method was called, the Page property for the data bound control was null!  It was being called before the page life cycle.  That was the other problem I was experiencing.  I'm going to look at changing the control to not take advantage of ViewState, letting the parent control handle that.  I'm also going to make it a WebControl, rendering the contents directly instead of using composition.  I think these are the keys to making it work correctly.

Posted by bmains | 231 comment(s)
Filed under: ,
I didn't realize that it was completed, but I found a link off of a forum site for an update to SQL Server Express, that looks really cool:  http://msdn.microsoft.com/vstudio/express/sql/download/

It allows express users to make use of Reporting Services, the new version of DTS, and the front-end GUI tool for SQL Server Management Studio, but for express.  Something that I could have used a while ago while loading data.  I'm glad they added all of these features; it's a great way to create some really cool applications.


Posted by bmains | with no comments
Filed under:

I made a mention in my last post that I had a property variable loaded and saved in control state.  Here is how control state works.  For properties that are definitely required, control state uses the same mechanism to store the data as view state (using a hidden field).  However, control state is used in situations where proper functioning of the control is needed for this property.  To restate, if you control has to have it definitely, where viewstate may not retain it if turned off, use control state.  Page developers can't turn it off, so you must be careful about what you do store in it.

To enable it, you must make a call to Page.RegisterRequiresControlState(this) in OnInit for it to enable loading and saving control state.  You can define the following methods as such:

protected override void LoadControlState(object savedState)
{
   Pair pair = savedState as Pair;
   if (pair != null)
   {
      base.LoadControlState(pair.First);
      _editItemIndex = (int)pair.Second;
   }
}

protected override object SaveControlState()
(
   return new Pair(base.SaveControlState(), _editItemIndex);
)

That's how you can use it.  You could use an object array or a Triplet object, or something else, which is determined in the Save method.

Posted by bmains | with no comments

Previously, I posted that child controls of a composite data bound control can post back for certain events, and yet the child control can retain its viewstate.  So what happens on the data bound control side?  The data bound control taps into the child events, having an Editing, Cancelling, and Updating, so when these happen, they handle the appropriate action at the parent level.  For instance, this property is needed, like in the GridView and DataGrid Controls.

public int EditItemIndex
{
   get { return _editItemIndex; }
   set { _editItemIndex = value; }
}

This property is loaded and saved using the control state.  Now, the editing event should set this edit index for the item being editing.  Updating updates the item's values, and cancelling cancels the edit.  One common denominator is that all of these events require reloading from the data source.  So, fo rthese events, we would have something like this:

protected void ChildControl_Editing(object sender, EventArgs e)
{
   //Sender is the child control; get a reference to it
   ChildControlType control = sender as ChildControlType;
   //In previous post, I stated child control has a DataItemIndex property
   this.EditItemIndex = control.DataItemIndex;

   //Rebind using the data source, which is another topic
}

protected void ChildControl_Updating(object sender, EventArgs e)
{
   //Get the original item index to update
   int oldIndex = this.EditItemIndex;
   //Reset the edit index
    this.EditItemIndex = -1;
     //Rebind using the data source
}

protected void ChildControl_Cancelling(object sender, EventArgs e)
{
    this.EditItemIndex = -1;
   //Rebind using the data source
}

All reset the edititemindex, and then rebind the data source, similar to what you had to do in 1.1 with the DataGrid.  The reason I put the comment in about Rebinding using the data source is because there are two scenarios.  The first is if binding with the datasourceid, which is more automatic for the page developer, and the second is more manual.

When binding with a data source control, you have access to the data source as needed.  The DataSourceView class returned from the GetData method can get the data, as well as perform the insert, update, and delete operations.  In our example above, when updating, that method will use the DataSourceView to update.  I will talk about the specifics later, mainly because I'm still learning them.

The other scenario is manually databinding, using the DataSource property.  This requires handling the updating and inserting.  As you see in the GridView or DetailsView controls, when using the DataSource property, you have to handle these yourself, or an error is thrown.  This is because the data source isn't preserved; only the results of the rendering through viewstate.

When using the data source id, for the events above, you can add these to rebind:

if (this.IsBoundUsingDataSourceID)
{
   this.RequiresDataBinding = true;
   this.EnsureDataBound();
}

This recreates the child controls (calls CreateChildControls again) with the updated data source.

Posted by bmains | with no comments
Filed under: ,
For this post, I want to focus on the repeated item in a data-bound control.  There are many ways to approach it; for what I am going to do, I created a custom control that renders as below:

My Title              Buttons
This is the text of my article.

The buttons invoke editing, which post back to the data bound parent control, noting that one of the controls in the collection is changing modes.

But first, I want to show how I created the child control to wire up.  Like the GridViewRow class, I created DataItem, DisplayIndex, and DataItemIndex properties defined in IDataItemContainer namespace.  These properties get populated on every load (not requiring viewstate), so I created a constructor:

public ChildDSControl(object dataItem, int dataItemIndex, DataControlRowState state)
{
    //Assign the values to the properties
}

Note that I didn't include DisplayIndex, because DataItemIndex and DisplayIndex are the same thing, and use the same variable.  I also added DataControlRowState, which invokes changing modes based on the type of mode we are in.  This is primarily for rendering, and has some functions in CreateChildControls.

Because it is a compositecontrol, I declare the following:

private WebControl _titleControl = null;
private WebControl _textControl = null;
private LinkButton _editButton =- null;
private LinkButton _saveButton = null;
private LinkButton _cancelButton = null;

Because Title and Text could be a label on readonly mode and textbox on edit mode, I use WebControl.  The DataControlRowState property determines which is rendered in the CreateChildControls method.  Because the controls will retain viewstate, the Title and Text properties are exposed, returning the control values.

Next, since each linkbutton is in the control collection, depending on the mode we are in, the appropriate one is rendered.  The click event is wired to an event handler, so when the button is clicked, it posts back.  Upon posting back, the control raises an event to the parent data control.  FOr instance, this custom control has the following events:

public event EventHandler Cancelling;
public event EventHandler Editing;
public event EventHandler Updating;

When the edit button is clicked, the linkbutton calls the event handler and raises the event:

protected void editButton_Click(object sender, EventArgs e)
{
    if (Editing != null)
       Editing(this, e);
}

This notifies the data bound control that the child control is being invoked into editing mode.  I handle this event in the data bound control, and I will post more about that at another time.  I hope this all makes some sense.  I plan to write an article in the future about it.  But for now, I hope I could provide some insight into part of the process.
Posted by bmains | with no comments
Well, I realized I was having more problems with that composite control a couple posts back.  To recap, I was creating a composite control with a title and text label/textbox in the format of:

Title      Buttons
Text

Somewhat like an article snippet on a news service, with the title above and the text below.  I added editing capabilities, so when the edit button was clicked, textboxes appeared, and when not, labels appeared.  This worked well.  But I was having problems with the buttons, as when Edit was clicked, the Save and Cancel buttons were shown.

I should also state these were wired to server events, so when clicked, it invoked code-behind, which raised the events to the composite data-bound control (next blog), and did the appropriate action.

So when the cancel button rendered, it didn't post back.  The problem was it wasn't in the control collection.  See, when in normal mode, I was only creating the edit button, and adding it to the control collection, and when in edit mode, creating the save and cancel buttons, and adding them to the collection at that time.  The problem was, on postback, the cancel button couldn't wire up because it didn't exist when it received the click event, and so it wasn't calling the handler, causing problems.

I ended up adding all buttons at all times to the control collection in CreateChildControls, which the control then worked.
Posted by bmains | with no comments

One of the aspects of custom control development is data-binding.  With the new data source controls in the 2.0 framework, custom control binding is easier to perform.  There are several properties and methods that are important to know:

IsBoundUsingDataSourceID - This property determines whether the control is bound using a data source control; if not, the developer has to manually program insert, update, delete, and select statements.
GetData - This method gets a DataSourceView class that interacts with the data source control.  It performs the actual insert, delete, update, and select work, and can verify whether these actions can be performed.
RequiresDataBinding - This property notes whether data binding is needed; after cancelling, editing, or updating actions, you need to set this to true.  RequiresDataBinding must be set to true before EnsureDataBound is called.
EnsureDataBound - This method makes sure the custom control is data bound.  When RequiresDataBinding property is true, the method binds the data to the control, which recreates the control collection.  If you debug your control, you will see the control build its structure based on the previous viewstate values, then rebuild with the new bound data source.

More on using these later.

Posted by bmains | with no comments
I had a problem with a composite control I was building; I tried several ways to implement it, either through the CreateChildControls and Render methods, or through Render only.  Neither approach worked.  What I was trying to do it output a label or textbox in this format:

My Title    Buttons (Edit or Save Cancel)
This is my text.

So it has a title, then to the right buttons to click, for editing and saving the changes, then text paragraphs below it.  My approach was to render labels for normal mode, then Textboxes for editing mode, as would appear in a gridview or detailsview control.  However, I couldn't get the links to render.

What I had forgotten to realize was I was rendering them in a server-based table control, then rendering the entire control in one shot.  It looked something like:

protected override void Render(HtmlTextWriter writer)
{
    Table table = new Table();
    table.Rows.Add(new TableRow());
    table.Rows.Add(new TableRow());

    TableCell cell = new TableCell();
    cell.Controls.Add(titleControl);    //Add my title control, whether textbox or label

    if (_editing)
    {
       //Render save/cancel buttons
       saveButton = new LinkButton();
       saveButton.ID = "save";
       saveButton.CommandName = "Save";
       saveButton.Text = "Save";
       saveButton.Click += new EventHandler(saveButton_Click);
    }
    else
    {
       //Render edit button
    }
   
    //continue processing

    table.RenderControl(writer);
}


The problem with this was I tried using the server-based method, but it would never post back (appeared as black text).  I even tried using IPostBackEventHandler and use client clicking, which worked, but didn't render as a link, it was only black text.  I had no idea why my links weren't links.

Then, through the help of joteke on forums.asp.net, I came to realize that the table was the issue.  writer.Write(..) the table out works fine; server-based table "shortcuts" don't work correctly.
Posted by bmains | with no comments
Filed under: ,

When creating custom controls, especially composite controls that can change their state from a readonly mode to an edit mode (switching controls that show the data from labels to text), the ITextControl interface comes in handy.  It defines the Text property so that you have a common base for these controls.  Instead of checking the control collection for label or textboxes separately, you can instead use ITextControl to bridge that gap and reduce code.  For instance, I had this property:

public class ExampleControl : CompositeControl
{
   private ITextControl _titleControl = null;
   private ITextControl _textControl = null;

   public string Title
   {
      get
      {
         this.EnsureChildControls();
         return _titleControl.Text;
      }
      set
      {
         this.EnsureChildControls();
         _titleControl.Text = value;
      }
   }
}

So, instead of having to check the control to see if it is a label or a textbox (because both inherit from WebControl, and this control doesn't have the text property), I can use ITextControl instead.  You can find more about it at:  http://msdn2.microsoft.com/en-us/library/system.web.ui.itextcontrol.aspx

Posted by bmains | with no comments
Filed under: ,

If you are looking to create custom data-bound controls, the Microsoft documentation has a few examples, including this walkthrough:

http://msdn2.microsoft.com/en-us/library/ms366539.aspx

What I have a hard time understanding is the code they recommend for the PerformSelect method.  The reason I have a hard time understanding it is because if you use the tool Reflector to look at the base DataBoundControl (which CompositeDataBoundControl inherits from), it already defines the code they recommend!

I would believe that I'm missing something, but it doesn't make sense to do something that is already done for you.  Any thoughts on the matter?

Posted by bmains | with no comments
Filed under: ,
More Posts Next page »