In this part we will derive from ObjectDataSource to put in place a hook that our selector can latch onto. When delving into the workings of the ObjectDataSource it also became clear that we have to also override the ObjectDataSourceView that it uses. The location of the hook actually sits here.
In the View we can actually override the ExecuteSelect command, this is the point at which the result of the BL method is found. So here it is:
// Copyright 2010 (c) Planet Software Pty Ltd. This work is
// licenced under the Creative Commons Attribution 2.5 Australia License. To view
// a copy of this licence, visit http://creativecommons.org/licenses/by/2.5/au/
public class QueryObjectDataSourceView : ObjectDataSourceView
{
public QueryObjectDataSourceView(QueryObjectDataSource owner, HttpContext context)
: base(owner, "DefaultView", context)
{
}
public event EventHandler<SelectEventArgs> QuerySelector;
protected override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
{
var result = base.ExecuteSelect(arguments);
if (QuerySelector != null && result is IQueryable)
{
var arg = new SelectEventArgs(result as IQueryable);
QuerySelector(this, arg);
result = arg.Query;
}
return result;
}
}
For completion here is the SelectEventArgs value:
public class SelectEventArgs : EventArgs
{
public SelectEventArgs(IQueryable query)
{
Query = query;
}
public IQueryable Query
{
get;
set;
}
}
Ok the hook is now in place in the View via the QuerySelector event. The next step is to expose this through the ObjectDataSource. There is a slight complication however, the default view is used internally by ObjectDataSource and all its properties are attached to this internal view. When we create the extended class we have to set this default view to our derived class which means we have to set a private property via reflection in SetBaseView():
// Copyright 2010 (c) Planet Software Pty Ltd. This work is
// licenced under the Creative Commons Attribution 2.5 Australia License. To view
// a copy of this licence, visit http://creativecommons.org/licenses/by/2.5/au/
public class QueryObjectDataSource : ObjectDataSource
{
private QueryObjectDataSourceView _queryView;
public QueryObjectDataSource()
: base()
{
SetBaseView();
}
public QueryObjectDataSource(string typeName, string selectMethod)
: base(typeName, selectMethod)
{
SetBaseView();
}
public event EventHandler<SelectEventArgs> QuerySelector
{
add { _queryView.QuerySelector += value; }
remove { _queryView.QuerySelector -= value; }
}
private void SetBaseView()
{
var prop = typeof(ObjectDataSource).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance);
prop.SetValue(this, GetView(null));
}
protected override DataSourceView GetView(string viewName)
{
if (_queryView == null)
{
_queryView = new QueryObjectDataSourceView(this, this.Context);
}
return _queryView;
}
}
I’ve also overridden the GetView class and also exposed the QuerySelector event in the View through the ObjectDataSource.
There now we have all the functionality of the ObjectDataSource with an added bonus of having a hook for changing IQueryable returns from called methods. In the next post we will discuss the need for our controls to expose a consistent interface about which fields it is binding to.
Print | posted on Sunday, 22 August 2010 5:53 PM