标签:silverlight wcf iis c1treeview c1flexgrid
I:项目描述:利用Silverlight+WCF技术,模拟资源管理器(如图1)功能,通过地址栏输入本地文件夹路径,然后将解析出来的该目录下所有文件(夹)存储到数据库中,然后再加载到界面上显示出来;IV:项目时间:2014/08/21-2014/09/04
V:项目源码:
一 项目架构(如图2)
(图2)
FolderDB:DAL(数据访问层),包括文件属性类Folders,文件夹树模型类FolderModel,数据库操作类DBHelper;
FolderUI:Silverlight客户端,基本界面显示,包括FlexGrid标题数据源类ColumnHeaders,文件大小值转换类FileSizeConverter;
FolderWCF:WCF服务层,包括FolderService服务类;
FolderWeb:Web层,该项目中涉及不多;
二 源码部分解析
源码文件:DBHelper.cs
/// <summary>
/// 执行多条SQL语句,实现数据库事务
/// </summary>
/// <param name="sqlStrList">多条SQL语句</param>
public int ExecuteSqlTran(List<string> sqlStrList)
{
SqlTransaction sqlTran = null;
try
{
if (ConnectionState.Open != m_SqlConn.State)
{
m_SqlConn.Open();
}
int count = 0;// 影响的记录数
SqlCommand cmd = new SqlCommand();
sqlTran = m_SqlConn.BeginTransaction();
cmd.Connection = m_SqlConn;
cmd.Transaction = sqlTran;
foreach (string sqlStr in sqlStrList)
{
if (sqlStr.Trim().Length > 1)
{
cmd.CommandText = sqlStr;
count += cmd.ExecuteNonQuery();
}
}
<span style="color:#ff0000;">sqlTran.Commit();// 提交数据库事务</span>
return count;
}
catch (SqlException sqlEx)
{
if (null != sqlTran)
{
sqlTran.Rollback();// 失败后回滚
}
throw new Exception(sqlEx.Message);
}
}注意执行完ExecuteNonQuery()后,并不算完,事务在最后还需要进行提交数据库事务才行,sqlTran.Commit(),否则操作一直都不会执行,但是调试过程中也不会出现异常;
源码文件:FolderModel.cs
public class FolderModel
{
/// <summary>
/// 当前目录(文件夹)属性
/// </summary>
public Folders <span style="color:#ff0000;">CurrFolder</span> { get; set; }
/// <summary>
/// 子文件(夹)集合
/// </summary>
public ObservableCollection<FolderModel> <span style="color:#ff0000;">SubFolders</span> { get; set; }
public FolderModel()
{
SubFolders = new ObservableCollection<FolderModel>();
}
public FolderModel(Folders folders)
{
CurrFolder = folders;
SubFolders = new ObservableCollection<FolderModel>();
}
}这是绑定C1TreeView控件的数据源模型,其中ObservableCollection是表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知。SubFolders则是作为子树的绑定,CurrFolder则是作为当前节点的绑定,详细见下面的XAML代码解释;
源码文件:ColumnHeader.cs
/// <summary>
/// Header数据源
/// </summary>
public class ColumnHeader : INotifyPropertyChanged
{
private List<string> m_HeaderList;
public event PropertyChangedEventHandler PropertyChanged;
public List<string> <span style="color:#ff0000;">HeaderList</span>
{
get
{
return m_HeaderList;
}
set
{
m_HeaderList = value;
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("HeaderList"));
}
}
}
}该类作为C1FlexGrid列标题即Column.Header的动态绑定数据源,HeaderList中存储的是每列的列名;该数据会从WCF服务端获取,然后绑定在客户端上显示; public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
int byteSize = int.Parse(value.ToString());// 单位字节
int nKBSize = (int)Math.Ceiling(byteSize * 1.0 / 1024);// 转换成KB
return string.Format("{0} KB", nKBSize);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}因为要将文件大小该列的值全部由字节转换成KB,则将Size那一列绑定该转换器即可;源码文件:MainPage.xaml
<UserControl x:Class="HuaweiSoftware.Folder.FolderUI.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
<span style="color:#ff0000;">xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml"</span>
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
<span style="color:#ff0000;">xmlns:sp="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"</span>
<span style="color:#ff0000;">xmlns:common="clr-namespace:System.Windows;assembly=System.Windows.Controls"</span>
<span style="color:#ff0000;">xmlns:local="clr-namespace:HuaweiSoftware.Folder.FolderUI"</span>
mc:Ignorable="d"
FontFamily="SimSum" FontSize="12"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<!-- 目录树数据源绑定 -->
<common:HierarchicalDataTemplate x:Key="<span style="color:#000099;">FolderTemplate</span>" ItemsSource="{Binding <span style="color:#ff0000;">SubFolders</span>}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding <span style="color:#33cc00;">CurrFolder.Name</span>}" />
</StackPanel>
</common:HierarchicalDataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid Grid.Row="0">
<!-- 路径输入框 -->
<Border Grid.Row="0" Height="23" BorderBrush="Black" BorderThickness="1" Margin="5,5,0,5">
<TextBox x:Name="txtPath" Height="23" />
</Border>
<Button x:Name="btnSave" Content="保存" Height="23" Width="60" Grid.Column="1" Click="SaveButton_Click" />
<Button x:Name="btnLoad" Content="加载" Height="23" Width="60" Grid.Column="2" Click="LoadButton_Click" />
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="70" />
</Grid.ColumnDefinitions>
</Grid>
<Grid Grid.Row="1" x:Name="grdContentArea">
<!-- 文件夹目录树 -->
<c1:C1TreeView x:Name="tvFoldersTree" Grid.Column="0" Margin="5,5,5,0" c1:C1NagScreen.Nag="True"
ItemsSource="{Binding <span style="color:#ff0000;">SubFolders</span>}"
ItemTemplate="{StaticResource <span style="color:#000099;">FolderTemplate</span>}"
SelectionChanged="FoldersTree_SelectionChanged"/>
<!-- 分界线 调整左右大小 -->
<sp:GridSplitter Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Stretch" Background="Black" Width="1" />
<!-- 文件夹下的文件列表 -->
<c1:C1FlexGrid x:Name="fgFilesView" c1:LicenseMode.Evaluation="True" AutoGenerateColumns="False"
Grid.Column="1" Margin="5,5,5,0" AllowSorting="True" IsReadOnly="True" AllowDragging="Both"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" SelectionMode="Row">
<c1:C1FlexGrid.Columns>
<c1:Column Binding="{Binding [2]}" HorizontalAlignment="Left" Width="200">
<c1:Column.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=HeaderList[2]}" />
</DataTemplate>
</c1:Column.HeaderTemplate>
</c1:Column>
<c1:Column Binding="{Binding [5]}" HorizontalAlignment="Left" Width="150" >
<c1:Column.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=HeaderList[5]}" />
</DataTemplate>
</c1:Column.HeaderTemplate>
</c1:Column>
<c1:Column Binding="{Binding [4]}" HorizontalAlignment="Left" Width="200" >
<c1:Column.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=HeaderList[4]}" />
</DataTemplate>
</c1:Column.HeaderTemplate>
</c1:Column>
<c1:Column Binding="{Binding [3]}" HorizontalAlignment="Right" Width="100" >
<c1:Column.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=HeaderList[3]}" />
</DataTemplate>
</c1:Column.HeaderTemplate>
</c1:Column>
</c1:C1FlexGrid.Columns>
</c1:C1FlexGrid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<!-- 信息提示栏 -->
<Border Grid.Row="2" Height="23" BorderBrush="Black" BorderThickness="1" Margin="5,0,5,5">
<TextBlock x:Name="txtMsg" Height="23" ToolTipService.ToolTip="信息提示" />
</Border>
<Grid.RowDefinitions>
<RowDefinition Height="33" />
<RowDefinition Height="*" />
<RowDefinition Height="33" />
</Grid.RowDefinitions>
</Grid>
</UserControl>C1TreeView控件:
ItemsSource="{Binding SubFolders}" ---- 绑定SubFolders数据源,该数据源在FolderModel类中定义,作为树数据源;
ItemTemplate="{StaticResource FolderTemplate}" ---- 指定树每个节点的模版定义;静态资源FolderTemplate则是在<UserControl.Resources>标签中定义;
HierarchicalDataTemplate:定义TreeView节点模版
ItemsSource="{Binding SubFolders}" ---- 同样指定该模版数据源
<TextBlock Text="{Binding CurrFolder.Name}" /> ---- 节点所包含的内容,绑定CurrFolder对象中Name属性值,在FolderModel类中定义;
C1FlexGrid控件:
AutoGenerateColumns="False" ---- 绑定数据源中有些列数据并不想显示出来,只要求部分指定的列显示,则需要设置成false,阻止其自动生成列;
<c1:C1FlexGrid.Columns> ---- 该标签下设置每列所绑定的数据
<c1:Column Binding="{Binding [2]}" HorizontalAlignment="Left" Width="200">
<c1:Column.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=HeaderList[2]}" />
</DataTemplate>
</c1:Column.HeaderTemplate>
</c1:Column> 该树绑定的数据源类型为List<List<string>>,所以Binding的对象就是List<string>类型,而按以往的思路,Binding的对象是具有get,set的属性,查看了List类下有public T this[int index] { get; set; },所以可以直接通过[n]索引来绑定数据;
HeaderTemplate作为Header的模版定义,绑定的数据源类型是ColumnHeader,直接访问其属性HeaderList即可;
源码文件:MainPage.xaml.cs
// 初始化
private void Init()
{
m_WCFClient = new FolderServiceClient();
m_WCFClient.SaveFoldersCompleted += SaveFoldersCompleted;
m_WCFClient.GetFoldersCompleted += GetFoldersCompleted;
m_WCFClient.GetFilesCompleted += GetFilesCompleted;
} FolderServiceClient是WCF服务代理对象,可以调用服务端相应的方法;这里的方法调用都是采用异步调用;
例如:想调用服务端SaveFolders(string path)方法,则在SaveFoldersCompleted绑定完成后,调用SaveFoldersAsync(str)方法即可,等待服务器端执行完SaveFolders方法返回给客户端时,客户端就会执行之前SaveFoldersCompleted绑定的方法;如下
void SaveFoldersCompleted(object sender, SaveFoldersCompletedEventArgs e)
{
if (null == e.Error)// 无异常
{
txtMsg.Text = e.Result + " 条数据导入。";
}
else// 异常,信息提示
{
this.txtMsg.Text = "数据导入异常,异常信息:" + e.Error.Message;
}
} 其中,e.Result的类型与服务器端SaveFolders方法的返回值类型一样,不需要转型;
// 加载数据库数据
private void LoadButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
m_WCFClient.GetFoldersAsync();// 直接从数据库中获取数据
txtMsg.Text = "正在直接从数据库中读取文件夹数据...";
fgFilesView.ItemsSource = null;
}
void GetFoldersCompleted(object sender, GetFoldersCompletedEventArgs e)
{
if (null == e.Error)// 无异常
{
if (null != e.Result)
{
tvFoldersTree.DataContext = e.Result;
txtMsg.Text = "从数据库中提取文件夹数据完成。";
}
else
{
txtMsg.Text = "数据库为空。";
}
}
else// 异常,信息提示
{
this.txtMsg.Text = "从数据库获取数据失败,异常信息:" + e.Error.Message;
}
} 从数据库中获取文件夹数据,返回后绑定文件夹树tvFoldersTree.DataContext=e.Result; 其中e.Result为FolderModel类型;
// 文件夹目录上的选择单个文件夹事件
private void FoldersTree_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
C1TreeViewItem selectedNode = tvFoldersTree.SelectedItem;
if (null != selectedNode)
{
// 当前选择的节点
FolderModel selectedFolderModel = (FolderModel)selectedNode.Header;
m_SelectedFolderName = selectedFolderModel.CurrFolder.Name;// 节点名称(文件夹名)
m_WCFClient.GetFilesAsync(selectedFolderModel.CurrFolder.ID);
}
}
void GetFilesCompleted(object sender, GetFilesCompletedEventArgs e)
{
if (null == e.Error)
{
List<List<string>> result = e.Result;
ColumnHeader columnHeader = new ColumnHeader();
columnHeader.HeaderList = result[0];
fgFilesView.ColumnHeaders.DataContext = columnHeader;// 绑定列标题数据源
result.RemoveAt(0);// 移除第一个表示列名称的List
fgFilesView.ItemsSource = new PagedCollectionView(result);// 绑定列内容数据源
fgFilesView.Columns[3].ValueConverter = new FileSizeConverter();
txtMsg.Text = "加载文件夹【" + m_SelectedFolderName + "】目录下的文件已完成。";
}
else
{
txtMsg.Text = "加载文件数据失败,异常信息:" + e.Error.Message;
}
} 添加文件夹树节点单击事件,在FlexGrid中加载该文件夹下所有文件信息;
C1TreeView的节点是C1TreeViewItem类型,所以获得当前点击的节点可以用:C1TreeViewItem selectedNode = tvFoldersTree.SelectedItem; 当然也可以由sender转型得到;值得注意的是,在这里,C1TreeViewItem的Header属性是C1TreeView所绑定数据源的类型,即FolderModel,而在xaml文件中,对Column标签的header属性进行值绑定时,其header值为string类型!!故在xaml中对header的绑定是通过HeaderTemplate模版定义来完成的;
服务器端返回的e.Result是一个List<List<string>>类型,其中第一个List<string>指的是列名;列名的绑定方式:fgFilesView.ColumnHeaders.DataContext = columnHeader; C1FlexGrid的绑定方式:fgFilesView.ItemsSource = new PagedCollectionView(result); 其中DataContext和ItemsSource两种是有区别的,本人还没有学习到,读者可以阅读他人的相关博文学习;
对第三列的文件大小需要绑定值转换器:fgFilesView.Columns[3].ValueConverter = new FileSizeConverter(); 即可;
源码文件:ServiceReferences.ClientConfig
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IFolderService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:54416/FolderService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IFolderService"
contract="FolderServiceRefer.IFolderService" name="BasicHttpBinding_IFolderService" />
</client>
</system.serviceModel>
</configuration> 该文件是由Silverlight客户端添加服务引用时自动生成的配置文件,其中<bindings>标签内容是由WCF服务器端的Web.config配置文件中对应的<bindings>标签内容截取部分而来,对于maxBufferSize和maxReceivedMessageSize两个属性最好设置值大一些,而且必须值一样,不能超过2147483647;否则会报如下异常:
1:“由于正在缓冲消息,MaxReceivedMessageSize 和 MaxBufferSize 的值必须相同”;
2:发生了System.ServiceModel.ProtocolException
Message=已超过传入消息(65536)的最大消息大小配额。若要增加配额,请使用相应绑定元素上的MaxReceivedMessageSize属性。
Source=System.ServiceModel
StackTrace:
在System.ServiceModel.Channels.HttpInput.ThrowHttpProtocolException(String messagem, HttpStatusCode statusCode, String statusDescription)
<endpoint>是客户端终结点设置,address属性指WCF所在服务器端的访问路径,其他属性内容也是从服务器端Web.config配置文件中自动生成过来的;
源码文件:IFolderService.cs
/// <summary>
/// FolderService服务接口
/// </summary>
[ServiceContract]
public interface IFolderService
{
[OperationContract]
int SaveFolders(string path);
[OperationContract]
FolderModel GetFolders();
[OperationContract]
List<List<string>> GetFiles(int pid);
} 专业名词叫“服务契约”,不专业的就知道它是个服务接口就ok了,这世界上知其然不知其所以然的东西多了个去了,你若计较你就输了,题外话,转正文;
接口上必须加[ServiceContract],方法上必须加[OperationContract];
源码文件:FolderService.svc和FolderService.svc.cs
<%@ ServiceHost Language="C#" Debug="true" Service="HuaweiSoftware.Folder.FolderWCF.FolderService" CodeBehind="FolderService.svc.cs" %>这是.svc文件里的内容,在VS里是无法编辑查看的,只有在文件目录下去找对应的文件打开编辑;
要注意的是,在修改了Service的路径后,需要手动来这里修改Service指配的路径,否则它不会自己改,编译时会报错;因为它是根据该文件去寻找Service的位置的;
SaveFolders方法:
DBHelper dbHelper = new DBHelper(m_DBConnString);
int count = 1;// 文件计数(索引ID)
List<Folders> folders = new List<Folders>();
try
{
DirectoryInfo rootFolderInfo = new DirectoryInfo(path);
Folders rootFolder = new Folders();
rootFolder.ID = 0;
rootFolder.PID = 0;
rootFolder.Name = rootFolderInfo.Name;
rootFolder.Type = "文件夹";
rootFolder.CreateTime = rootFolderInfo.CreationTime;
folders.Add(rootFolder);// 添加文件夹根节点
GetSubFolders(ref count, 0, ref folders, path);// 迭代找到所有子目录
// 数据库操作
List<string> sqlStrList = new List<string>();
sqlStrList.Add("TRUNCATE TABLE Folders");// 清空表中数据
foreach (Folders folder in folders)
{
string strSql = string.Format("INSERT INTO " + m_TableName +
" VALUES({0},{1},'{2}',{3},'{4}','{5}')",
folder.ID, folder.PID, folder.Name, folder.Size, folder.Type, folder.CreateTime);
sqlStrList.Add(strSql);
}
int nCount = dbHelper.ExecuteSqlTran(sqlStrList);// 增加的记录数
return nCount;
} 1)记得把当前文件夹的节点加入,即rootFolder;只有根节点(rootNode)的ID和PID值相等,且等于0;
2)文件夹未设置的Size属性,在存入数据库中是NULL值,再次读取出来的时候要注意值判断;
3)GetSubFolders方法是一个迭代函数,详解见下面;
4)在导入数据库之前需要先清空数据表Folders表中数据,“TRUNCATE TABLE Folders”比“DELETE FROM Folders”执行效率高;
5)执行多条SQL语句,采用事务;
GetFolders方法
string strSql = "SELECT ID,PID,Name,Size,Type,CreateTime FROM " + m_TableName +
" WHERE Type='文件夹'" +
" <span style="color:#cc0000;">ORDER BY ID</span>";
DBHelper dbHelper = new DBHelper(m_DBConnString);
m_AllFolders = new List<Folders>();
try
{
// 从数据库中获取指定数据
SqlDataReader dataReader = dbHelper.ExecuteReader(strSql);
while (dataReader.Read())
{
Folders folder = new Folders();
folder.ID = dataReader.GetInt32(0);
folder.PID = dataReader.GetInt32(1);
folder.Name = dataReader.GetString(2);
// 文件夹的类型Type为NULL,故不读取
folder.Type = dataReader.GetString(4);
folder.CreateTime = dataReader.GetDateTime(5);
m_AllFolders.Add(folder);
}
dataReader.Close();
// 迭代得到文件目录树
if (m_AllFolders.Count > 0)
{
FolderModel folderModel = new FolderModel();
FolderModel rootFolderModel = new FolderModel(m_AllFolders[0]);
folderModel.SubFolders.Add(rootFolderModel);
MakeTreeModel(0, ref rootFolderModel);
return folderModel;
}
else
{
return null;
}
} 1)在从数据库中选取所有文件夹时,记得对ID排序,将root节点放在第一个!
2)得到的List<Folders>结果集,需要转换成树模型FolderModel;如下图:
3)MakeTreeModel函数是一个迭代函数,详情见下面;
GetFiles方法
<strong> </strong>string strSql = "SELECT ID,PID,Name,Size,Type,CreateTime FROM " + m_TableName +
" WHERE PID=" + pid + " AND Type<>" + "'文件夹'";
DBHelper dbHelper = new DBHelper(m_DBConnString);
List<List<string>> resultList = new List<List<string>>();
List<string> headerList = new List<string>() { "ID", "PID", "Name", "Size", "Type", "CreateTime" };
resultList.Add(headerList);// 添加列标题
try
{
SqlDataReader dataReader = dbHelper.ExecuteReader(strSql);
while (dataReader.Read())
{
List<string> itemList = new List<string>();
itemList.Add(dataReader.GetInt32(0).ToString());
itemList.Add(dataReader.GetInt32(1).ToString());
itemList.Add(dataReader.GetString(2));
itemList.Add(dataReader.GetInt32(3).ToString());
itemList.Add(dataReader.GetString(4));
itemList.Add(dataReader.GetDateTime(5).ToString("yyyy/MM/dd hh:mm"));
resultList.Add(itemList);
}
return resultList;
} 1)查找指定PID的所有文件(非文件夹,即Type不等于文件夹)
2)SqlDataReader读取数据库中数据时,通过类似于 Get类型(int index) 这种方法获得,当数据库中数据为空时,该方法会报出异常,项目中没有对此进行判断,此处mark一下(dataReader.IsDBNull(0)判断第一个数据是否为空);
3)DateTime输出成指定格式:DateTime.ToString("yyyy/MM/dd hh:mm");
GetSubFolders方法
string[] folders = Directory.GetDirectories(path);
string[] files = Directory.GetFiles(path);
if ((null != files) && (files.Length > 0))// 如果存在文件
{
foreach (string file in files)
{
FileInfo fileInfo = new FileInfo(file);
Folders folder = new Folders();
folder.ID = id;
id++;
folder.PID = pid;
folder.Name = fileInfo.Name;// 文件名
folder.Size = (int)fileInfo.Length;// 文件大小
folder.Type = GetFileType(file);// 文件类型
folder.CreateTime = fileInfo.CreationTime;// 文件创建时间
allFolders.Add(folder);
}
}
if ((null != folders) && (folders.Length > 0))// 如果存在文件夹
{
foreach (string folder in folders)
{
DirectoryInfo folderInfo = new DirectoryInfo(folder);
Folders newFolder = new Folders();
newFolder.ID = id;
id++;
newFolder.PID = pid;
newFolder.Name = folderInfo.Name;
newFolder.Type = "文件夹";
newFolder.CreateTime = folderInfo.CreationTime;
allFolders.Add(newFolder);
GetSubFolders(ref id, newFolder.ID, ref allFolders, folder);// 迭代进入子目录
}
} 1)获取目录下所有文件及文件夹,并添加到allFolders集合中;
2)若是文件夹,则将(当前文件ID+1,当前文件ID作为子目录下文件节点的PID,allFolders,当前文件夹路径)作为参数迭代入子目录中;
GetFileType方法
ShellClass shell = new ShellClass();
Shell32.Folder dir = shell.NameSpace(Path.GetDirectoryName(filePath));
FolderItem item = dir.ParseName(Path.GetFileName(filePath));
return dir.GetDetailsOf(item, 2);
/**
* 2 FileType; 9 FileAuthor; 10 FileTitle; 11 FileSubject; 12 FileCategory; 14 FileComment
*/ 对于文件类型,FileInfo的Extension属性只是文件的扩展名而已,要获得文件完整的文件类型,需要调用COM组件中的Shell32.dll控件;
MakeTreeModel方法
// 利用LINQ检索查找父节点id=pid的所有子节点
var subFoldersTemp = from folder in m_AllFolders
where folder.PID == pid
select folder;
List<Folders> subFolder = subFoldersTemp.ToList<Folders>();
if (subFolder.Count > 0)// 如果存在子目录
{
foreach (Folders folder in subFolder)// 遍历所有子目录文件(文件夹)
{
bool isRootNode = (folder.ID == folder.PID);// 是Root节点
bool isFolderNode = folder.Type.Equals("文件夹");// 是文件夹
if ((!isRootNode) && isFolderNode)// 如果是文件夹且不是root节点
{
FolderModel folderModel = new FolderModel();
folderModel.CurrFolder = folder;
subFolderModel.SubFolders.Add(folderModel);
MakeTreeModel(folder.ID, ref folderModel);// 进入子目录迭代
}
}
} 这个函数是根据List<Folders>数据集合生成相对应的目录树对象FolderModel;
源码文件:Web.config
<appSettings>
<add key="connString" value="Data Source=CWJSJ-1404-008\SQLEXPRESS;Initial Catalog=folder;User ID=sa;Password=sa" />
<add key="tableName" value="Folders" />
</appSettings> 数据库参数配置;也可以通过<connectionstring>标签来配置;
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IFolderService"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="myBehavior" name="HuaweiSoftware.Folder.FolderWCF.FolderService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IFolderService" contract="HuaweiSoftware.Folder.FolderWCF.IFolderService"></endpoint>
</service>
</services>
</system.serviceModel> 指定了behaviour和binding两个配置;binding标签内的属性设置,有一部分会自动生成到客户端的配置文件中,对maxBufferSize和maxReceivedMessageSize两个属性的设置尤其注意;
service标签则是对FolderService服务的设置,behaviourConfiguration,name,binding=basicHttpBinding,bindingConfiguration,contract的属性值都要和指定的路径或者配置对应上,不可随意命名;
三 项目遇到的问题及参考解决方法
1:WCF的独立调试
参考解决方法:将WCF项目“设为启动项目”,并将svc文件“设为起始页”,然后按“F5”即可打开“WCF测试客户端”,如下图,然后选择要是调试的方法(如SaveFolders()),在右侧的“值”中填入所需参数(字符串里需要转义),再执行“调用”即可在“响应”中看到结果值;如果在VS中相应的方法中加入断点,则可以进行断点调试操作!
2:WCF测试客户端的配置文件
参考解决方法:上图中,在“配置文件”上右键选择“用SvcConfigEditor进行编辑”选项,即可对WCF测试客户端的配置文件进行修改;
尤其是出现“已超过传入消息(65536)的最大消息大小配额。”的异常信息时,需要修改其中“绑定”目录下已定义的basicHttpBinding属性配置信息,将其中的MaxBufferPoolSize和MaxBufferSize和MaxReceivedMessageSize的值均改为int的MaxValue即可;
还有,每次打开该SvcConfigEditor,程序都会自动重新加载“个人文件夹\AppData\Local\Temp\Test Client Projects\11.0\f868aff1-aa2d-4418-abaf-f4be03a71529”下的Client.dll.config配置文件,f868aff1-aa2d-4418-abaf-f4be03a71529这个根据情况会有所变动,这样之前的属性配置修改就白搭了,每次启动都要修改,这丫的肯定不干了呀,在WCF测试客户端里,在“工具”-》“选项”中,把“始终在启动服务时重新生成配置”选项去掉就欧克了!
3:没有异常,重新生成解决方案也都成功,但是启动Silverlight后界面上完全空白
参考解决方法:毫无头绪的bug呀,而且是深藏不露的!通过启动Web端的界面也无法显示Silverlight程序,而且查看了Silverlight中xaml文件下也无异常情况,此时此刻,可以肯定的是加载Silverlight过程中出错了,没有正常加载Silverlight!但是又如何知道是什么bug,什么地方出现了bug呢?
在Web项目中找到要加载Silverlight应用程序的aspx页面文件,将onSilverlightError该函数内的errMsg错误信息弹出显示即可;
这时候再根据错误提示去找度娘就简单多了,2103的错误解决如下:
由于在修改Silverlight客户端的命名空间时,导致项目内部没有彻底完全的修改完命名空间,才会导致2103错误;在Silverlight项目右键属性中,查看“启动对象”是否是修改命名空间后的选项即可;
4:在Silverlight客户端添加服务引用时,异常“找不到类型Project.Web.Service,它在ServiceHost指令中提供为Service特性值,或在配置元素...”
如果,我说的是如果,你已经完全确定你的WCF服务完全正确,Web.config配置里也完全正确,那这个错误只可能是因为你在WCF项目中编辑完服务之后,没有对WCF项目“重新生成”导致的!!这也提醒着大家,在项目编码过程中,每次对WCF项目进行编辑修改后,都要重新生成一下,并且在Silverlight客户端的服务上右键“更新服务引用”才行,不然你改了半天的WCF服务端方法,结果执行的结果依然让人寒心,那就真的寒心了... ...
5:项目的部署问题
VS默认是采用自带的IIS Express来部署Silverlight项目以及WCF服务,部署后在右下角会出现如下图标和内容;
关于IIS Express和本地的IIS的区别,是一个很有意思的话题,这里就不说了,建议去看大神博客解析,会受益匪浅的。这里简单提及一些基本的关于IIS Express知识:
配置文件:C:\Program Files\IIS Express\AppServer\applicationhost.config
<applicationPools>标签 ---- 应用程序池配置
<add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
相当于IIS中
<sites>标签 ---- 网站配置,每一个<site>子标签,代表一个网站的配置
<site name="Development Web Site" id="1" serverAutoStart="true">
<application path="/">
<virtualDirectory path="/" physicalPath="%IIS_BIN%\AppServer\empty_wwwroot" />
</application>
<bindings>
<binding protocol="http" bindingInformation=":8080:localhost" />
</bindings>
</site><defaultDocument>标签 ---- 设置默认起始页
<files>
<add value="Default.htm" />
<add value="Default.asp" />
<add value="index.htm" />
<add value="index.html" />
<add value="iisstart.htm" />
<add value="default.aspx" />
</files>其他的可以自行了解去了!
Silverlight+WCF部署在本地IIS上,需要注意事项:
1)WCF项目和SilverlightWeb项目发布到IIS网站下的相同目录下,
2:作为第二次发布的项目,不能选择“发布前删除所有现有文件”,否则会把前一个发布的文件清除了;
3:发布目录下的配置文件Web.config检查一下是不是WCF项目中的配置文件,如果不是,手动粘贴过来覆盖
4:修改ClientBin\*.xap\ServiceReferences.ClientConfig文件中,关于WCF服务地址的终结点配置,改为本地ip地址;
5:应用程序“DEFAULT WEB SITE”中的服务器错误;HTTP 错误 403.14-Forbidden;Web服务器被配置为不列出此目录的内容。
因为部署的项目中没有默认的启动页面,IIS设置的默认启动页面文档包括【“Default.htm”,“Default.asp”,“index.htm”,“index.html”,“iisstart.htm”,default.aspx】,而你部署的项目根目录下没有这些文档中的至少一个,而且,在IIS功能视图中的“目录浏览”设置里也禁用了,所以报此错误!解决方法自己去搞定吧!!
6:直接访问svc服务文件(http://192.168.0.64/FolderService.svc)报如下异常:
当前已禁用此服务的元数据发布。
如果之前在VS上调试一切正常,只是发布后出现这个问题,去发布目录下查看配置文件Web.config,看是否是WCF项目下的那个配置文件,不是的话就手动拷贝覆盖。
否则的话就按浏览器下面出现的异常提示解决:
7:... ...未完待续
标签:silverlight wcf iis c1treeview c1flexgrid
原文地址:http://blog.csdn.net/missstar0617/article/details/39079017