接上回,现在我们来实现风险测试模块的测试题界面,这里主要是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;
}
}