You don't have to create separate methods and classes for each value type. While unfortunately you can't marshall base object types or use generics with RIA services, you can use a generic object type for the RadObservableCollection on the client side, and achieve a similar effect using an object with individual properties for each data type you use and the null coalescing operator to select the value in use on the client side.
For example.
Code behind on the client side. In this case my user control is called PersonList:
The DistinctValue model object definition is simply as follows:
Note that I have continued to call the string Value property just "Value". This maintains compatibility with Rosens original solution and allows this modification to drop in seemlessly to existing solutions. String filters will continue to :just work"
As helper function on my Domain Service I have the following:
public
partial
class
CostService
{
static
Expression<Func<T,
string
>> CreateSelectorExpression<T>(
string
propertyName, ParameterExpression parameterExpression=
null
, MemberExpression parentPropertyExpression=
null
)
{
if
(parameterExpression==
null
)
parameterExpression = Expression.Parameter(
typeof
(T));
if
(propertyName.Contains(
"."
))
{
var properties = propertyName.Split(
new
char
[] {
'.'
}, 2);
MemberExpression propExpression =
Expression.Property(parentPropertyExpression
as
Expression ?? parameterExpression
as
Expression, properties[0]);
return
CreateSelectorExpression<T>(properties[1], parameterExpression, propExpression);
}
else
{
return
(Expression<Func<T,
string
>>)Expression.Lambda(Expression.PropertyOrField(parentPropertyExpression
as
Expression ?? parameterExpression
as
Expression, propertyName), parameterExpression);
}
}
static
List<DistinctValue> _distinctValueList(IQueryable<
string
> values)
{
return
_distinctValueList<
string
>(values);
}
static
List<DistinctValue> _distinctValueList<T>(IQueryable<T> values)
{
var list =
new
List<DistinctValue>();
int
i = 0;
if
(values !=
null
)
{
foreach
(var value
in
values)
{
if
(value
is
DateTime)
{
list.Add(
new
DistinctValue() { ID = i, DateValue = value
as
DateTime? });
}
else
{
list.Add(
new
DistinctValue() { ID = i, Value = value
as
String });
}
i++;
}
}
return
list;
}
}
Firstly there is a slight modification of Rosens CreateSelectorExpression function that supports creating expressions for Navigation properties.
Next there is a helper function that returns a list of distinct values given a list of strings. This is just a stub that calls the generic helper function that creates a list of distinct values for any type (to maintain compatibility with my previous string only code). Turns out that numeric types work just fine when converted to string (so you probably don't really need the IntValue and probably FloatValue properties, but there may be some corner cases so I left them in). You definitely need DateTime properties to filter on date types though.
Finally, here is an example of a GetDistinctValues function that uses the above code. Note that I specifically trap my non-string properties in a case statement and manually create expressions rather than use CreateSelectorExpression. It would probably not be alot of trouble to modify CreateSelectorExpression to handle non string types, however as I only have a couple of instances where this is required (and I am stupidly busy) I have not undertaken the exercise.