Silverlight for KPI
题外话先:早些时候一同事问我KPI到底是咋回事,我用标准的解释方法说了好几遍都没听懂,后来干脆直接跟他说------GDP,他叹了口气,委屈的说知道了.(GDP是公司近段时间提出的个人产值的指标,达到这个就保持你的工资,达不到就扣你20%工资,有啥概念还有比这更深入人心呢,唉,可恶的经济危机啊)
写此篇受到李兄很大的启发.一直以来就有用类似WPF来实现BI的想法,只是由于个人原因迟迟没有实现.不过最近看到WXWinter(冬)的工作流作品深受鼓舞.
为什么要wpf/silverlight for KPI or BI?笔者评估过很多工具或者第三方组件,都是纯asp.net control,他们在运行起来需要加载大量的javascript,容易导致浏览器死掉,而且还要区分浏览器类型和版本.通过flash或者silverlight这种方式多少可以避开这样的问题,而且展现形式要更灵活.
先写KPI,原因是发现这个实现起来相对来说要简单一些,本文最终完成的效果是这个样子的:
关于KPI的详细解释,请参考微软的这篇文档.这里简要按照个人的理解说一下一些用到的概念:
首先是”目标”,其实按照字面理解就可以,就是一个用来衡量的标准,”值”,就是实际是多少,这个值和目标做比较,在KPI应用中,通常没有达到的就显示个红灯以示警告,跟这个值差不多就显示一个黄灯,超过目标一个指定的范围就现实一个绿灯,这种通过红黄绿的标识可以理解为其中的”状态”.
明确以上的概念,那么在silverlight中显示KPI就不难了,实际上就是怎么把状态值显示成相关的图片.
首先,在silverlight中要面对数据通信的问题,silverlight不像WPF 桌面应用,客户端无法ADO.NET,更别提ADOMD.NET了,所以需要通过WebService或者其它的类似方案,在WebService里引用ADOMD.NET对Analysis Services进行操作.
查询的语法通常是如下的格式(SQLServer2005/2008通用的SSAS):
SELECT
{ KPIValue("Channel Revenue"),
KPIGoal("Channel Revenue"),
KPIStatus("Channel Revenue"),
KPITrend("Channel Revenue")
} ON Columns,
Descendants
( { [Date].[Fiscal].[Fiscal Year].&[2002],
[Date].[Fiscal].[Fiscal Year].&[2003],
[Date].[Fiscal].[Fiscal Year].&[2004]
}, [Date].[Fiscal].[Fiscal Quarter]
) ON Rows
FROM [Adventure Works]
查询的结果通常如下图所示:
为了大家能在下载后看到KPI效果图,本文省略服务编写的步骤(如果有必要会在续篇中详细说明),另外大家很可能没有对应版本的分析服务,所以本文的数据是简单的测试数据,大致如下:
List<People> source = new List<People>();
source.Add(new People { name = "北京市", value1 = 1532, value2 = 851, field1 = 1, field2 = 0, field3 = 0, field4 = 1 });
source.Add(new People { name = "上海市", value1 = 358, value2 = 1785, field1 = -1, field2 = 0, field3 = -1, field4 = 0 });
source.Add(new People { name = "深圳市", value1 = 2564, value2 = 3584, field1 = 1, field2 = 1, field3 = -1, field4 = 0 });
source.Add(new People { name = "天津市", value1 = 1256, value2 = 258, field1 = -1, field2 = -1, field3 = -1, field4 = -1 });
source.Add(new People { name = "长春市", value1 = 3112, value2 = 2586, field1 = 1, field2 = 1, field3 = 1, field4 = 0 });
source.Add(new People { name = "沈阳市", value1 = 1584, value2 = 1258, field1 = -1, field2 = -1, field3 = -1, field4 = 0 });
source.Add(new People { name = "青岛市", value1 = 3587, value2 = 1256, field1 = 0, field2 = 0, field3 = -1, field4 = 0 });
dgTest.ItemsSource = source;
没错,这里用到的就是Silverlight2中的DataGrid,这个控件是个很灵活的控件.实际上到silverlight这一层处理就很简单了,因为它接收的除了目标值等这样的信息外,KPI状态值如上所示就是简单的状态值.
接下来需要做绑定值的转换,通常单元格里接收到的值就是-1,0,1(当然也会有-1,-0.3,0,0.3,1这样的情况,本文只考虑三种情况),所以这里的问题是如何把这样的值转换成小红灯,小黄等或者小绿灯这样的控件.这样的图片来源很广泛,可以在素材网站里找,也可以用微软sqlserver下现成的,就像李兄在文中提到的.不过在silverlight下需要多做一个工作,就是把sqlserver带的这些gif图片转成jpg的,否则会出问题.Sqlserver中带了好几个样式,挑自己觉得好看的用fireworks这样的工具转一下就ok了.
关于值转换这里有一个跟webapp和winform程序都不大一样的地方,笔者认为也是最别扭的一个地方.按照之前的理解,把KPI状态显示封装成一个usercontrol,然后暴露出一个属性供DataGrid的模板列中传递绑定的值给它就可以了,然后usercontrol里获得这个值决定显示哪张图片.但在把绑定的值给usercontrol的这个属性的时候出现了莫名其妙的问题.还好在qq的wpf silverlight群10458228里得到高人的指点,用Converter.于是我在yahoo里搜索(中文网站上资料太少),按照其方法写了如下类.
public class KPIImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int kpivalue = (int)value;
BitmapImage source=new BitmapImage();
switch (kpivalue)
{
case -1:
source.UriSource = new Uri("Images/KPI/stoplight_single0.jpg", UriKind.Relative);
break;
case 0:
source.UriSource = new Uri("Images/KPI/stoplight_single1.jpg", UriKind.Relative);
break;
case 1:
source.UriSource = new Uri("Images/KPI/stoplight_single2.jpg", UriKind.Relative);
break;
}
return source;
}
public object ConvertBack(object value,Type targetType,object parameter,CultureInfo culture)
{
//Visibility visibility = (Visibility)value;
//return (visibility == Visibility.Visible);
return null;
}
}
然后在页面里做如下声明:
<UserControl.Resources>
<SilverlightApplication1:KPIImageConverter x:Key="KPIValueConverter" />
</UserControl.Resources>
然后用DataGrid的模板列,这里的思路跟asp.net的差不多.
<data:DataGridTemplateColumn Header="帅哥产量状态" Width="80">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Image Width="16" Height="16" Source="{Binding field1, Converter={StaticResource KPIValueConverter}}" />
</StackPanel>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
基本上实现的时候步骤和需要注意的地方就是这些,特意在这里说明一下,好让更多碰到类似问题的朋友都能找到解决的方法.此文描述的方法适用于SQLServer2005和SQLServer2008中的Analysis Services.
最后,请注意crossdomain的问题,请看我之前关于此的描述:
http://www.cnblogs.com/aspnetx/archive/2008/04/19/1161734.html
总结:
总体来说WPF for BI是个不错的方案,不过让我感到奇怪的是国内外还没有见到有人做过相关的应用,多少可能是由于BI到底要render到什么程度很难找到一个标准,但确实不应该质疑WPF或者Silverlight的能力.
相关资源:
微软的示例数据库,数据仓库,分析模型下载,有2000和 2005的:
http://www.codeplex.com/MSFTDBProdSamples
如何在SQLServer中定义和浏览KPI:
http://msdn.microsoft.com/zh-cn/library/ms166869(SQL.90).aspx
---------------------------------------------------------------
aspnetx的BI笔记系列索引:
使用SQL Server Analysis Services数据挖掘的关联规则实现商品推荐功能
---------------------------------------------------------------