有的大牛只写怎样怎样理解概念,喜欢讲一些概念,有的大牛干脆不写技术,有的大牛只会唯利是图,卖一些组件,我不是大牛,我喜欢帮助别人。 今天我们看看档案管理界面的数据查询与展示,先上一张图,调一下胃口。 这个界面主要的看点有DataGrid数据展示,分组,分页,Convert的使用等。首先我们来看一下界面的代码,这个布
有的大牛只写怎样怎样理解概念,喜欢讲一些概念,有的大牛干脆不写技术,有的大牛只会唯利是图,卖一些组件,我不是大牛,我喜欢帮助别人。
今天我们看看档案管理界面的数据查询与展示,先上一张图,调一下胃口。
这个界面主要的看点有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>
<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
这个写法是因为假如我们要给列头国际化,因为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;
}
}
}
{
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;
}
{
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中有这么一段代码,就是获取到数据源以后,我们
从前台代码我们可以看出,分页按钮的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;
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);
}
{
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() };
}
{
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,我可以共享给大家。
本文出自BruceAndLee 博客,请务必保留此出处http://leelei.blog.51cto.com/856755/902131
http://silverlightchina.net/html/tips/2012/0618/16796.html