有的大牛只写怎样怎样理解概念,喜欢讲一些概念,有的大牛干脆不写技术,有的大牛只会唯利是图,卖一些组件,我不是大牛,我喜欢帮助别人。
今天我们看看档案管理界面的数据查询与展示,先上一张图,调一下胃口。
这个界面主要的看点有DataGrid数据展示,分组,分页,Convert的使用等。首先我们来看一下界面的代码,这个布局方式采用Grid+StackPanel布局,代码如下。
<controls:ChildWindow.Resources> <StateConvert:ArchiveStateConvert x:Key="ArchiveConvert"></StateConvert:ArchiveStateConvert> <StateConvert:SexConvert x:Key="SexConvert"></StateConvert:SexConvert> <LocalResource:ArchiveManageResource x:Key="LocalResource"></LocalResource:ArchiveManageResource> <Style x:Key="ColumnHeaderStyle" TargetType="sdk:DataGridColumnHeader"> <Setter Property="FontSize" Value="12"></Setter> </Style> </controls:ChildWindow.Resources> 省略部分代码 <TextBlock Text="{Binding tb_Name,Source={StaticResource LocalResource}}" Margin="10,0,0,0" FontSize="12" Grid.Row="0" Grid.Column="5"/> <sdk:AutoCompleteBox Width="130" FontSize="12" Grid.Row="0" Grid.Column="6" ItemsSource="{Binding PersonList,Mode=OneWay}" SelectedItem="{Binding SelectedPerson,Mode=TwoWay}"/> <StackPanel Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="3" Margin="0,5,0,0" Orientation="Horizontal" HorizontalAlignment="Center"> <Button Content="{Binding btn_Search,Source={StaticResource LocalResource}}" Command="{Binding QueryCommands}" FontSize="12" Width="90" Margin="0,0,5,0"/> <Button Content="{Binding btn_Reset,Source={StaticResource LocalResource}}" FontSize="12" Width="90"/> </StackPanel> </Grid> </Border> <sdk:DataGrid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" IsReadOnly="True" x:Name="dgArchiveList" ItemsSource="{Binding MyCollectionViewSource.View,Mode=OneWay}" AutoGenerateColumns="False" AlternatingRowBackground="Silver" ColumnHeaderHeight="20" FrozenColumnCount="3" CanUserReorderColumns="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" AreRowGroupHeadersFrozen="False" SelectionMode="Single" CanUserSortColumns="False" LoadingRowGroup="MyDataGrid_LoadingRowGroup"> <sdk:DataGrid.Columns> <!--<sdk:DataGridTemplateColumn Header="选择"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox Checked="{Binding IsChecked,Mode=TwoWay}"/> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn>--> <sdk:DataGridTextColumn Binding="{Binding ArchiveState,Mode=OneWay,Converter={StaticResource ArchiveConvert}}"> <sdk:DataGridTextColumn.HeaderStyle> <Style TargetType="sdk:DataGridColumnHeader"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <TextBlock Text="{Binding Grid_Header_ArchiveState,Source={StaticResource LocalResource}}"/> </DataTemplate> </Setter.Value> </Setter> <Setter Property="FontSize" Value="12"/> </Style> </sdk:DataGridTextColumn.HeaderStyle> </sdk:DataGridTextColumn> <sdk:DataGridTextColumn HeaderStyle="{StaticResource ColumnHeaderStyle}" Header="档案编号" Binding="{Binding ArchiveNo,Mode=OneWay}" /> 省略部分代码 </sdk:DataGrid.Columns> </sdk:DataGrid> 省略部分代码 <StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0"> <HyperlinkButton x:Name="linkFirst" Foreground="Blue" Tag="First" IsEnabled="{Binding IsLinkFirstEnable,Mode=OneWay}" Click="HyperlinkButton_Click" Content="{Binding link_First,Source={StaticResource LocalResource}}" FontSize="12"/> <HyperlinkButton x:Name="linkPrevious" Foreground="Blue" Tag="Previous" IsEnabled="{Binding IsLinkPreviousEnable,Mode=OneWay}" Click="HyperlinkButton_Click" Content="{Binding link_Previous,Source={StaticResource LocalResource}}" FontSize="12"/> <HyperlinkButton x:Name="linkNext" Foreground="Blue" Tag="Next" IsEnabled="{Binding IsLinkNextEnable,Mode=OneWay}" Click="HyperlinkButton_Click" Content="{Binding link_Next,Source={StaticResource LocalResource}}" FontSize="12"/> <HyperlinkButton x:Name="linkLast" Foreground="Blue" Tag="Last" IsEnabled="{Binding IsLinkLastEnable,Mode=OneWay}" Click="HyperlinkButton_Click" Content="{Binding link_Last,Source={StaticResource LocalResource}}" FontSize="12"/> </StackPanel> </controls:ChildWindow>
查询条件中使用了AutoComplete,<sdk:AutoCompleteBox Width="130" FontSize="12" Grid.Row="0" Grid.Column="6" ItemsSource="{Binding PersonList,Mode=OneWay}" SelectedItem="{Binding SelectedPerson,Mode=TwoWay}"/>。首先其ItemsSource绑定的是一个List<string>,SelectedItem绑定的是选择项,我们看看效果。
当我在姓名文本框中输入“李”的时侯,所有姓李的人都列出来了。当我选择了一个人名以后,SelectedPerson的值将会变为我选择的人名,因为SelectedPerson是个双向绑定。ok我们再往下看,我们发现前台代码的DataGrid列中有这么一行。
<sdk:DataGridTextColumn Binding="{Binding ArchiveState,Mode=OneWay,Converter={StaticResource ArchiveConvert}}"> <sdk:DataGridTextColumn.HeaderStyle> <Style TargetType="sdk:DataGridColumnHeader"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <TextBlock Text="{Binding Grid_Header_ArchiveState,Source={StaticResource LocalResource}}"/> </DataTemplate> </Setter.Value> </Setter> <Setter Property="FontSize" Value="12"/> </Style> </sdk:DataGridTextColumn.HeaderStyle> </sdk:DataGridTextColumn>
这个写法是因为假如我们要给列头国际化,因为DataGrid的DataGridTextColumn的Header是不可以绑定Resource文件的(因为ColumnHeader是DependencyObject类型的,而不是DepenencyProperty),所以我们只能给它指定Style。这就是这个列和其他列不同的原因,其他列是直接设置Header的。OK,再看这么一段代码
<sdk:DataGridTextColumn HeaderStyle="{StaticResource ColumnHeaderStyle}" Header="性别" Binding="{Binding Sex,Mode=OneWay,Converter={StaticResource SexConvert}}"/>
我们发现Binding中有个Converter属性,这个是用来转换性别的,假如Sex的值是1,转换为男,假如是0,转换为女。首先需要在页面引用这个实现了IValueConverter 的类,如上代码xmlns:StateConvert="clr-namespace:Client.Common;assembly=Common"先引用命名空间,在引用类<StateConvert:SexConvert x:Key="SexConvert"></StateConvert:SexConvert>,我们看看这个SexConvert 类,如下
namespace Client.Common { public class SexConvert : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string s = (string)value; switch (s) { case "1": s = "男"; break; case "0": s = "女"; break; } return s; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { string strValue = value.ToString().Equals("男") ? "1" : "0"; return strValue; } } }
实现Convert和ConvertBack即可。接下来我们要看的是DataGrid的分页和分组,和上一篇文章一样,查询绑定的是Command,所以逻辑都在ViewModel中。我们看看代码
public ICommand QueryCommands { get { QueryCommand queryCommand = new QueryCommand(); queryCommand.Query += delegate() { this.CurrentPage = 1; var queryRequest = new SearchRequest() { ArchiveNo = this.ArchiveNo, GraduateStartDate = this.StartDate, GraduateEndDate = this.EndDate, Name = this.SelectedPerson, Sex = this.Sex, BirthDay = this.BirthDay, IdCard = this.IdCard, Professional = this.Professional, GraduateSchool = this.GraduateSchool, Education = this.Education, ArchiveState = this.ArchiveState, PageIndex = -1, PageSize = this.PageSize }; GetData(queryRequest); }; return queryCommand; } } public void GetData(SearchRequest queryRequest) { string requestStr = SeriealizeHelper<SearchRequest>.JsonSerialize<SearchRequest>(queryRequest); ArchiveInfoService.ArchiveInfoServiceClient client = new ArchiveInfoService.ArchiveInfoServiceClient(); List<ArchiveInfoEntity> list = new List<ArchiveInfoEntity>(); client.GetPersonInfoListCompleted += delegate(object sender, ArchiveInfoService.GetPersonInfoListCompletedEventArgs e) { ArchiveInfoEntity entity; e.Result.PersonInfoList.ForEach(r => { entity = new ArchiveInfoEntity(); entity.IsChecked = false; entity.ArchiveNo = r.no; entity.ArchiveState = r.state; entity.BirthDay = r.birth; entity.Education = r.education_level; entity.GraduateSchool = r.graduate_school; entity.GraduateYear = r.graduate_year; entity.IdCardNo = r.id_card; entity.IsChecked = false; entity.Name = r.name; entity.Professional = r.professional; entity.Sex = r.sex; list.Add(entity); }); this.RecordCount = e.Result.RecordCount; this.TotalPage = e.Result.RecordCount % PageSize == 0 ? e.Result.RecordCount / PageSize : e.Result.RecordCount / PageSize + 1; this.SetLinkBtnEnable(queryRequest); CollectionViewSource collectionViewSource = new CollectionViewSource(); collectionViewSource.Source = list; collectionViewSource.GroupDescriptions.Add(new PropertyGroupDescription("ArchiveState")); this.MyCollectionViewSource = collectionViewSource; }; client.GetPersonInfoListAsync(requestStr); } private void SetLinkBtnEnable(SearchRequest request) { this.SetLinkEnable(true); if (this.TotalPage <= 1) { this.SetLinkEnable(false); } if (request.PageIndex == this.TotalPage-2) { this.IsLinkNextEnable = false; this.IsLinkLastEnable = false; } if (request.PageIndex == -1 && this.TotalPage > 1) { this.IsLinkFirstEnable = false; this.IsLinkPreviousEnable = false; } } private void SetLinkEnable(bool isEnable) { this.IsLinkFirstEnable = isEnable; this.IsLinkLastEnable = isEnable; this.IsLinkNextEnable = isEnable; this.IsLinkPreviousEnable = isEnable; }
从前台代码我们可以看出,分页按钮的isEnabled状态分别绑定ViewModel中的IsLinkFirstEnable ,IsLinkLastEnable,IsLinkNextEnable,IsLinkPreviousEnable。在GetData中有这么一段代码,就是获取到数据源以后,我们对其进行了分组,
this.RecordCount = e.Result.RecordCount; this.TotalPage = e.Result.RecordCount % PageSize == 0 ? e.Result.RecordCount / PageSize : e.Result.RecordCount / PageSize + 1; this.SetLinkBtnEnable(queryRequest); CollectionViewSource collectionViewSource = new CollectionViewSource(); collectionViewSource.Source = list; collectionViewSource.GroupDescriptions.Add(new PropertyGroupDescription("ArchiveState")); this.MyCollectionViewSource = collectionViewSource;
我们获取到分页数据以后,根据ArchiveState属性进行分组,然后绑定到界面,注意,DataGrid界面绑定代码ItemsSource="{Binding MyCollectionViewSource.View,Mode=OneWay}",注意在这里是MyCollectionViewSource.View。接下来是分页,分页是我自己定义的一个分页。我们看看页面cs代码
private void HyperlinkButton_Click(object sender, RoutedEventArgs e) { HyperlinkButton hyperLink = sender as HyperlinkButton; var queryRequest = new SearchRequest() { ArchiveNo = archiveModel.ArchiveNo, GraduateStartDate = archiveModel.StartDate, GraduateEndDate = archiveModel.EndDate, Name = archiveModel.SelectedPerson, Sex = archiveModel.Sex, BirthDay = archiveModel.BirthDay, IdCard = archiveModel.IdCard, Professional = archiveModel.Professional, GraduateSchool = archiveModel.GraduateSchool, Education = archiveModel.Education, ArchiveState = archiveModel.ArchiveState, PageSize = archiveModel.PageSize, }; switch (hyperLink.Tag.ToString()) { case "First": archiveModel.PageIndex = -1; break; case "Next": archiveModel.PageIndex++; break; case "Previous": archiveModel.PageIndex--; break; case "Last": archiveModel.PageIndex = archiveModel.TotalPage-2; break; } archiveModel.CurrentPage = archiveModel.PageIndex + 2; queryRequest.PageIndex = archiveModel.PageIndex; archiveModel.GetData(queryRequest); }
在分页的时候调用ViewModel的GetData方法,在ViewModel中动态的设置分页按钮的enabled状态。为了方便大家理解我的意思,我会把ViewModel的cs作为附件供大家下载。ok,我们看看服务端分页代码,如下
public SearchResponse GetPersonInfoList(string searchRequest) { SearchRequest searchRequests = SerializeHelper.JsonDeserialize<SearchRequest>(searchRequest); IQueryable<Person_Info> personInfo = misInfoEntities.person_info .Where(p => (string.IsNullOrEmpty(searchRequests.ArchiveNo) ? true : searchRequests.ArchiveNo.Contains(p.no)) && (string.IsNullOrEmpty(searchRequests.Name) ? true : p.name == searchRequests.Name) && (string.IsNullOrEmpty(searchRequests.Sex) ? true : p.sex == searchRequests.Sex) && (string.IsNullOrEmpty(searchRequests.IdCard) ? true : p.id_card.Contains(searchRequests.IdCard)) && (string.IsNullOrEmpty(searchRequests.Professional) ? true : p.professional == searchRequests.Professional) && (string.IsNullOrEmpty(searchRequests.Education) ? true : p.education_level == searchRequests.Education) && (string.IsNullOrEmpty(searchRequests.ArchiveState) ? true : p.state == searchRequests.ArchiveState) && (!searchRequests.GraduateStartDate.HasValue ? true : p.graduate_year >= searchRequests.GraduateStartDate.Value.Year) && (!searchRequests.GraduateEndDate.HasValue ? true : p.graduate_year <= searchRequests.GraduateEndDate.Value.Year) && (!searchRequests.BirthDay.HasValue ? true : p.birth == searchRequests.BirthDay)); IEnumerable<Person_Info> personInfos = personInfo.AsEnumerable().OrderBy(p => p.name) .Skip(searchRequests.PageSize * (searchRequests.PageIndex + 1)) .Take(searchRequests.PageSize); foreach (var person in personInfos) { person.education_level = misInfoEntities.codes.SingleOrDefault(c => c.ename == "EDUCATION" && c.data == person.education_level).display_content; } return new SearchResponse() { PersonInfoList = personInfos.ToList(), RecordCount = personInfo.Count() }; }
在这里因为我的服务端的数据访问层是EF,所以采用的是LINQ to Entities的方式。今天就写到这里,因为篇幅有限,有很多代码没有贴,需要代码的同志可以留言,我可以发给大家,或者加入.net群205217091,我可以共享给大家。