Josh Heyse

Thoughts Defragmented

Archive for May, 2008

A Richer DynamicDataFilter – Part 5 ColumnContains

Posted by jheyse on 23rd May 2008

I’m not really sure what to call this post, so it’s just the name of the control I wrote.  A reader left me the following message on a previous post during this series on the extended DynamicDataFilter:

Hi

I was wondering if you could guide me on how to do the following:

On every List page, I need a dropdownlist populated with  all the column names from the Table. Adjacent to that should be a textbox where the user can enter some text. And then a ‘Search’ button.

When clicked on this button, the following should happen:

Perform search on the Table where dropdownlist.selectedcolumnname CONTAINS textbox.text.

Repopulate Gridview with the search results.

I’d appreciate any help or atleast an idea on how to go about this. I’m new to Dynamic Data

Abby, unfortunately the functionality you are looking for isn’t currently supported in DynamicData, the main issue is that the LinqDataSource does not understand CONTAINS the where parameters you supply are all equals.  But, the DynamicData Filtering I have written does support this. (My code isn’t production quality, and should only be used in production at your own risk.)  Here is a quick screen shot:

ColumnContains

To allow for this I created a ColumnContains control which has a DrowDownList of the columns available in the DataSource’s Table and a TextBox which accepts your CONTAINS value.

<table>
    <tr>
        <td>
            <asp:DropDownList ID="ddlColumn" runat="server">
            </asp:DropDownList>
        </td>
        <td>
            <asp:TextBox ID="tbText" runat="server"></asp:TextBox>
        </td>
    </tr>
</table>

The code behind for the control is responsible for binding the list of string based columns to the DropDownList and creates the LikeExpressionParameter which is responsible for the LIKE query.

public partial class ColumnContains : Catalyst.Web.DynamicData.FilterTemplateUserControlBase
{
    protected void Page_Init(object sender, EventArgs e)
    {
        ddlColumn.DataTextField = "Name";
        ddlColumn.DataSource = Table.Columns.Where(c => c.TypeCode == TypeCode.String);
        ddlColumn.DataBind();
    }

    private MetaTable Table
    {
        get
        {
            IDynamicDataSource source = this.FindDataSourceControl();
            if(source != null)
                return source.GetTable();
            return null;
        }
    }

    public override IEnumerable<Parameter> GetWhereParameters(IDynamicDataSource dataSource)
    {
        yield return new LikeExpressionParameter()
            {
                Name = ddlColumn.SelectedValue,
                Like = LikeExpressionParameter.LikeType.Contains,
                Value = tbText.Text
            };
    }

    public MetaColumn Column
    {
        get
        {
            return Table.GetColumn(ddlColumn.SelectedValue);
        }
        set
        {
            ddlColumn.SelectedIndex = -1;
            if (value != null)
            {
                ListItem li = ddlColumn.Items.FindByValue(value.Name);
                if (li != null)
                    li.Selected = true;
            }
        }
    }

    public string Value
    {
        get
        {
            return tbText.Text;
        }
        set
        {
            tbText.Text = value;
        }
    }

    public override void LoadQueryStringParameters(NameValueCollection parameters)
    {
        string columnName = parameters[string.Format("{0}_column", this.ID)];
        Column = Table.GetColumn(columnName);
        Value = parameters[string.Format("{0}_value", this.ID)];
    }

    public override NameValueCollection SaveQueryStringParameters()
    {
        NameValueCollection collection = new NameValueCollection();
        collection.Add(string.Format("{0}_column", this.ID), Column.Name);
        collection.Add(string.Format("{0}_value", this.ID), Value);
        return collection;
    }

    public override void Clear()
    {
        Column = null;
        Value = string.Empty;
    }
}

Posted in ASP.NET, C#, Dynamic Data, LINQ | 1 Comment »

Line of Business Applications in Silverlight 2

Posted by jheyse on 22nd May 2008

A majority of the Silverlight demos I have seen focus on the graphical features such as gradients, layout and animations.  I’m constantly impressed with eye candy the designers who have taken on the Silverlight space create.  I am not that guy.  My graphical design ineptitude is a only surpassed by my lack of musical aptitude.

My role as an architect and developer is to quickly bring business value to my clients.  This is typically done by automating processes and providing intuitive user interfaces.  Up to now, the easiest platform to accomplish those goals has been WinForms.  WinForms, isn’t the ultimate solution though, you have platform limitations, deployment issues and of course it doesn’t run in the cloud.  So, what’s the answer? There still isn’t, and never will be an ultimate solution, but I believe Silverlight 2 is the best option for rapidly developing a connected rich user interface.

So, why Silverlight for business applications?

  • Cross Platform Support
  • Reuse of existing .NET Business Objects
  • WPF DataBinding, Layout, and Styles
  • No-touch deployment

I recently gave a 70 minute presentation at the IndyCodeCamp on LOB applications in Silverlight 2.  For the presentation I created a simple CRM application which has the following entities: Contact, Phone, & Address.  The entities are stored in a SQL Server database using LINQ-to-SQL for the data access layer.  The entities are exposed to the Silverlight application via WCF services, which with a small hack allow you to share the same Business Objects library between the ASP.NET application which hosts the WCF service and the Silverlight application.  The Silverlight UI is modeled after the Office 2007 contacts screens, kind of boring but again, I’m not that guy.

The Solution

BusinessObjects

The BusinessObjects project holds the C# objects for the entities of the application.  This includes things like the Address, AddressList, Contact, etc…  This is a pretty standard BusinessObjects library with two things to note:

  • DataContact and DataMember attributes are included to allow for WCF communication
  • The project is a Silverlight Library which allows for compilation to a true .NET assembly
  • (see this post for more info)

CRM_Web

The CRM_Web project is the ASP.NET web project which hosts the CRM Silverlight app and the WCF services which provide the data to the client.  When you create a Silverlight 2 app in Visual Studio 2008, this project will automatically be created for you with a directory named ClientBin.  This is the ‘working directory’ for you Silverlight app.  In this directory you will see a file named CRM.xap, think of this as your application exe.  It is the assembly that is executed within the browser on the client side.  In the project you will also see several files in the Services directory, this is the code for the WCF service.

CRM

So, on to the good stuff and a picture is worth a thousand words:

CRMThe entry point for the application is a UserControl, all screens are UserControls, there is no concept of a Form in Silverlight, which has a DataGrid displaying the contacts in the system.  I have limited it to the top 5 because responsiveness was a little slow, I am looking into this and waiting for the DataVirtualization features slated for Silverlight 2 beta 2.

I have simulated Modal windows using the Popup control and a well skinned Dialog control I created.  I am going to be continuing development on the Dialog control to add some of the missing features of a standard modal window.

I am going to cut this blog entry here, but I will go into more detail on some of the more interesting concepts in the demo in later posts.  For now here are the slide deck and demo from the IndyCodeCamp:

Download Solution – CRM.zip

Posted in Silverlight | No Comments »

Encapsulation Generation Tool

Posted by jheyse on 21st May 2008

Last week I was helping out on a project and there was a need to encapsulate or wrap an existing type to extend some functionality.  The reason was that functionality in the soon to be encapsulated type could not be extended due to a majority of the members being final, or non-overridable.  Wrapping a class can be an extremely tedious exercise, especially if there are many public members.  I am disappointed too see that this isn’t one of the refactoring tools built into Visual Studio. 

EncapsulateToolI thought that this would be a good exercise to familiarize myself with CodeDom and Visual Studio integration. The CodeDom, while complicated isn’t that bad; VS integration on the other hand is a serious pain, so I have decided to forgo the second half of the excessive and the functionality will have to remain in a stand alone tool.

Here is a screen shot of the finished application.  It allows you specify a type to encapsulate, target language and your new class and namespace.

I am not going to bore you with the details of the CodeDom code, it’s pretty easy to follow and I am attaching the code example. 

 

 

 

There are two limitations to the tool:

  • it does not wrap events. In an ideal world the wrapper class would declare the event and delegate the add/remove accessors to the encapsulated class. CodeDom does not supporte the add/remove accessors.
  • it does not wrap properties with indexers, I believe CodeDom supports this, I didn’t bother to figure out how to do this.

There you go Ben.

Download Solution – Encapsulate.zip

Posted in .NET, C#, Visual Studio | No Comments »

Safe Binding using Lambdas

Posted by jheyse on 19th May 2008

Friday I was discussing some of the new features in Visual Studio 2008 SP1 with some co-workers and one of them mentioned a new feature where VS 2008 will do symbolic renaming on all WCF Service Artifacts.  This lead to a conversation on how the IDE understands properties and methods differently then their corresponding names in XML configuration files (WCF) and string literals (data binding).  During the conversation I had a small light come on, regarding data binding and string literals. 

With .NET 3.5 it is possible to do compile time checking for data binding using Lambda expressions.  The idea is that instead of using a string to represent the name of the property you would pass in a Lambda Expression referencing that property.  Here is a simple example using a business object property that raises PropertyChanged.

public class Person : INotifyPropertyChanged
{
    private string _name;
 
    public string Name
    {
        get { return _name; }
        set
        {
            if (!object.Equals(_name, value))
            {
                _name = value;
                OnPropertyChanged(() => Name);
            }
        }
    }
 
    private void OnPropertyChanged(Expression<Func<object>> property)
    {
        MemberExpression me = property.Body as MemberExpression;
        if (me == null)
            throw new ArgumentException("property.Body must be of type MemberExpression", "property");
 
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(me.Member.Name));
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
}

The first benefit you get by doing this is that when you use the VS IDE refractoring tools to rename Name, the IDE will find Name in the Lambda expression and rename it there as well.  It is also possible to create type safe implementation using a generic base class:

public class BusinessBase<TObject> : INotifyPropertyChanged
{
    protected bool SetHelper<T>(Expression<Func<TObject, object>> property, ref T field, T value)
    {
        MemberExpression me = property.Body as MemberExpression;
        if (me == null)
            throw new ArgumentException("property.Body must be type MemberExpression", "property");
 
        if (!object.Equals(field, value))
        {
            field = value;
            OnPropertyChanged(me.Member.Name);
            return true;
        }
        return false;
    }
 
    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
}

and it’s corresponding implementation:

public class Person : BusinessBase<Person>
{
 
    private string _name;
 
    public string Name
    {
        get { return _name; }
        set { SetHelper<string>(p => p.Name, ref _name, value); }
    }
 
}

Honestly, I am not crazy about the second implementation which requires inheriting from a generic class and giving it a concrete implementation, which locks you into always being BusinessBase<Person> when you’ve extended Person to be Employee.  I will have a serious of blogs posts on some of these issues, with my Core series soon.

So anyway, enough with the business objects, lets look at databinding. Currently in .NET you create a binding between a control and an object using the following code:

this.firstTextBox.DataBindings.Add(new Binding("Text", this.personBindingSource, "First", true));

This loosely couples the Text property of the firstTextBox TextBox to the First property of some object, referenced by personBindingSource.  Once the designer generates this code, it is not checked against the actually objects.  Using Lambda Expressions the previous line of code could be implemented like:

this.firstTextBox.DataBindings.Add(
    new ExpressionBinding<TextBox, Person>(c => c.Text, this.personBindingSource, p => p.First, true));

where the definition of ExpressionBinding extends Binding:

public class ExpressionBinding<TControl, TDataSource> : Binding
    {
        public ExpressionBinding(Expression<Func<TControl, object>> property, object dataSource, Expression<Func<TDataSource, object>> dataMember)
            : this(property, dataSource, dataMember, false, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
        { }
 
        public ExpressionBinding(Expression<Func<TControl, object>> property, object dataSource, Expression<Func<TDataSource, object>> dataMember, bool formattingEnabled)
            : this(property, dataSource, dataMember, formattingEnabled, DataSourceUpdateMode.OnValidation, null, string.Empty, null)
        { }
 
        public ExpressionBinding(Expression<Func<TControl, object>> property, object dataSource, Expression<Func<TDataSource, object>> dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode)
            : this(property, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, null, string.Empty, null)
        { }
 
        public ExpressionBinding(Expression<Func<TControl, object>> property, object dataSource, Expression<Func<TDataSource, object>> dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue)
            : this(property, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, string.Empty, null)
        { }
 
        public ExpressionBinding(Expression<Func<TControl, object>> property, object dataSource, Expression<Func<TDataSource, object>> dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString)
            : this(property, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, null)
        { }
 
        public ExpressionBinding(Expression<Func<TControl, object>> property, object dataSource, Expression<Func<TDataSource, object>> dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo)
            : base((property.Body as MemberExpression).Member.Name, dataSource, (dataMember.Body as MemberExpression).Member.Name, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, formatInfo)
        { }
    }

Unfortunately, this implementation is not practical in WinForms since the current Visual Studio designer does not support lambda expressions for binding.   I would be interested to see if the WinForms team is looking into improved implementations of data binding with the 3.5 technologies. 

Posted in .NET, C#, LINQ, Visual Studio | No Comments »

Twitter

Posted by jheyse on 1st May 2008

Over the weekend I presented at the Indy Code Camp.  Within minutes of sitting down at the speaker’s table I was asked if I had a Twitter account.  Actually, it was more like "Hi, I’m Dan. What’s your twitter account?"  So, by the end of the day I had signed up for a twitter account.

I know I’m probably the last person alive to join the Twitter crowd. But, now that I have conformed I am enjoying my assimilation. Twitter is just so simple, it’s great. The greatest feature I have seen so far is the ability to post status messages and view updates via gtalk.

Follow me at: http://twitter.com/jheyse

Posted in Speaking | No Comments »