接上回,现在我们来实现风险测试模块的测试题界面,这里主要是ItemsControl控件与ListBox控件的使用以及WCF的应用。
如图
类似这样的内容,应该不会想手动去添加每一项吧,没错,应该是数据库查询,然后绑定才对,在web中,我们可以两个repeater搞定,那么在sl里呢?应该也有类似的办法吧,不过找来找去,没有发现所谓的repeater或者datalist,只是找到了一个ItemsControl,那么这个是不是我们想要的东西呢?管它呢,先拿出来看看。
新建一个测量题页面,结构如下
页面有了,我们再来搞定数据,数据库也是来源于之前的项目,这里直接使用了,在服务器,我用IIS来承载WCF,在WCF中使用实体框架edmx,先添加所需项
WCF服务
实体模型
然后选择从数据库生成,新建到数据库的连接
从数据库表中选择我们需要的表
F6编译一下,然后我们在我们的项目中添加对WCF服务的引用,如
现在,我们的项目结构如
这些基本都是自动生成的,不用管它,编译完全没有问题,现在我们添加我们需要的服务
[ServiceContract]
public interface IWcfService
{
/// <summary>
/// 获取风险测试题
/// </summary>
/// <returns></returns>
[OperationContract]
List < TB_SYS_DangerTestQuestions > GetRiskTest();
}
public class WcfService : IWcfService
{
public List < DAL.TB_SYS_DangerTestQuestions > GetRiskTest()
{
using (var entities = new DAL.WFT_101104Entities())
{
var q = entities.TB_SYS_DangerTestQuestions.ToList();
return q;
}
}
}
在风险测试模块的测试题列表页
WcfService.WcfServiceClient client = new WcfService.WcfServiceClient();
void RiskTestPage_Loaded( object sender, RoutedEventArgs e)
{
client.GetRiskTestCompleted += new EventHandler < WcfService.GetRiskTestCompletedEventArgs > (client_GetRiskTestCompleted);
client.GetRiskTestAsync();
}
void client_GetRiskTestCompleted( object sender, WcfService.GetRiskTestCompletedEventArgs e)
{
result = e.Result;
this .icRiskQ.ItemsSource = result.Where(o => string .Compare(o.PID, " 0 " ) == 0 ).ToList();
}
运行下看看吧,出错了,在 .xap 应用程序包中无法找到“ServiceReferences.ClientConfig”。
嗯,动态加载的问题,因为模块被动态加载后,程序读的xap包就是主程序的XAP包了,所以提示说找不到配置文件,那我们只要在主程序中添加同一个WCF服务的引用,并使用同一个名称就可以。(正常应用中,也建议把服务引用统一放置,而不是每个项目都去添加服务引用)
现在再试,题目出来了,但接下来的实现可就花费了我好长的时间,按照传统,在ItemControl控件的ItemTemplete中,我再加入一个ItemControl,然后开始寻找印象中的ItemDataBound事件。。。没有!没关系,没有这个事件,那我就在子控件的load事件中绑定,哈哈,轻易搞定!(这里需要借助控件的Tag属性)
private void icRiskA_Loaded( object sender, System.Windows.RoutedEventArgs e)
{
ItemsControl ic = sender as ItemsControl;
ic.ItemsSource = result.Where(o => string .Compare(o.PID, ic.Tag.ToString()) == 0 ).ToList();
}
但这还没完,试着点点看看,不错,还没有提定RadioButton的分组,这个也好办,绑定PID就行了,但真正的问题来,当我试图取每道题的结果时,我没有办法了。。。
网上疯狂寻找办法,参考这个贴子
http://www.cnblogs.com/wackelbh/archive/2010/11/12/1984043.html
那么我们如何获取DataTemplate中的名为txtID的TextBox控件或者其它控件呢?
在test.xaml.cs文件中不能够直接引用名为txtID的TextBox控件,即this.txtID是不能访问的,因为txtID只属于DataTemplate模板的名称空间范围内(类似于参数的作用域),可参看Silverlight4文档的TemplatePartAtrribute。
对于
TextBox txtBox = (TextBox)VisualTreeHelper.GetChild(this.cmbTemplate.LoadContent(), 0);
因为它的Text的值是绑定数据源的ID属性(如:{Binding Path=ID}),通过程序运行动态生成的值,因此通过这两种方式获得的TextBox的Text是空值,而对于tbCategoryName名的TextBlock,因为它的Text值是固定的“Name”字符串,因此通过这两种方法获得的TextBlock的Text值为“Name”。
总之,我也没找到更好的实现,那就由了它吧,我也换ListBox了,这个例子网上就好多了,我直接给出代码了
< ItemsControl x:Name ="icRiskQ" Margin ="20" >
< ItemsControl.Template >
< ControlTemplate >
< ItemsPresenter Margin ="0,0,2,2" />
</ ControlTemplate >
</ ItemsControl.Template >
< ItemsControl.ItemTemplate >
< DataTemplate x:Name ="icRiskQDT" >
< StackPanel >
< StackPanel Orientation ="Horizontal" >
< Image Source ="/Images/ico01.jpg" Stretch ="Fill" VerticalAlignment ="Center" />
< TextBlock x:Name ="textBlock" FontSize ="12"
Text =" {Binding ItemText} " Foreground ="#FFD2CDCD" d:LayoutOverrides ="Width" />
</ StackPanel >
< ListBox x:Name ="lbRiskA" Tag =" {Binding GUID} " Loaded ="icRiskA_Loaded" Margin ="20,0,0,0" Background =" {x:Null} " BorderThickness ="0" >
< ListBox.ItemTemplate >
< DataTemplate >
< TextBlock Text =" {Binding ItemText} " Tag =" {Binding ItemValue} " Foreground ="#FFD2CDCD" />
</ DataTemplate >
</ ListBox.ItemTemplate >
< ListBox.ItemContainerStyle >
< Style TargetType ="ListBoxItem" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate TargetType ="ListBoxItem" >
< Grid Background ="Transparent" HorizontalAlignment ="Left" VerticalAlignment ="Center" >
< RadioButton IsChecked =" {TemplateBinding IsSelected} " IsHitTestVisible ="False" >
< ContentPresenter />
</ RadioButton >
</ Grid >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
</ ListBox.ItemContainerStyle >
</ ListBox >
</ StackPanel >
</ DataTemplate >
</ ItemsControl.ItemTemplate >
</ ItemsControl >
这里有个建议,虽然读xaml代码会帮助理解,但千万不要陷入xaml的海洋,能用工具还是用工具吧,比如blend。
这样,我们取值时就好办多了,而且有需要可还以做到选择验证,并且让ScrollView定位到具体题目位置(这个我也是找了好半天才找到的,sl的中文资料还是太少了。。。)
for ( int i = 0 ; i < this .icRiskQ.Items.Count; i ++ )
{
var o = this .icRiskQ.ItemContainerGenerator.ContainerFromIndex(i);
StackPanel sp = (StackPanel)VisualTreeHelper.GetChild(o, 0 );
ListBox lb = (ListBox)sp.FindName( " lbRiskA " );
var q = lb.SelectedItem as WcfService.TB_SYS_DangerTestQuestions;
if (q == null )
{
MessageBox.Show( " null answer! " );
var gt = sp.TransformToVisual( this .mp.SVMain);
Point position = gt.Transform( new Point( 0 , 0 ));
this .mp.SVMain.ScrollToVerticalOffset( this .mp.SVMain.ScrollableHeight + position.Y);
return ;
}
else
{
allvalue += q.ItemValue.Value;
}
}