【Silverlight】Folder项目_总结回顾

【Silverlight】Folder项目_总结回顾,第1张

概述I:项目描述:利用Silverlight+WCF技术,模拟资源管理器(如图1)功能,通过地址栏输入本地文件夹路径,然后将解析出来的该目录下所有文件(夹)存储到数据库中,然后再加载到界面上显示出来; II:涉及技术:Silverlight;WCF;Component One控件(TreeView和FlexGrid) III:开发环境:Visual Studio2012;SQL Server 2008 I:项目描述:利用Silverlight+WCF技术,模拟资源管理器(如图1)功能,通过地址栏输入本地文件夹路径,然后将解析出来的该目录下所有文件(夹)存储到数据库中,然后再加载到界面上显示出来;

II:涉及技术:Silverlight;WCF;Component One控件(TreeVIEw和FlexGrID)

III:开发环境:Visual Studio2012;sql Server 2008 R2;Silverlight 5;Component One C1Silverlight_2014v1;

IV:项目时间:2014/08/21-2014/09/04


V:项目源码:



(图1)

一  项目架构(如图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 >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 >CurrFolder</span> { get; set; }        /// <summary>        /// 子文件(夹)集合        /// </summary>        public ObservableCollection<FolderModel> <span >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

@H_301_74@ /// <summary> /// header数据源 /// </summary> public class Columnheader : INotifyPropertyChanged { private List<string> m_headerList; public event PropertyChangedEventHandler PropertyChanged; public List<string> <span >headerList</span> { get { return m_headerList; } set { m_headerList = value; if (PropertyChanged != null) { PropertyChanged.Invoke(this,new PropertyChangedEventArgs("headerList")); } } } }该类作为C1FlexGrID列标题即Column.header的动态绑定数据源,headerList中存储的是每列的列名;该数据会从WCF服务端获取,然后绑定在客户端上显示;

源码文件:fileSizeConverter.cs

        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 >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 >xmlns:sp="clr-namespace:System.windows.Controls;assembly=System.windows.Controls"</span>    <span >xmlns:common="clr-namespace:System.windows;assembly=System.windows.Controls"</span>    <span >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 >FolderTemplate</span>" ItemsSource="{Binding <span >SubFolders</span>}">            <StackPanel OrIEntation="Horizontal">                <TextBlock Text="{Binding <span >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,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,0" c1:C1NagScreen.Nag="True"                           ItemsSource="{Binding <span >SubFolders</span>}"                           ItemTemplate="{StaticResource <span >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,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,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,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 >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,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错误信息d出显示即可;


这时候再根据错误提示去找度娘就简单多了,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服务,部署后在右下角会出现如下图标和内容;

@H_68_403@@H_920_404@



关于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项目下的那个配置文件,不是的话就手动拷贝覆盖。

否则的话就按浏览器下面出现的异常提示解决:

总结

以上是内存溢出为你收集整理的【Silverlight】Folder项目_总结回顾全部内容,希望文章能够帮你解决【Silverlight】Folder项目_总结回顾所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1013354.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存