【Silverlight】模仿Windows资源管理器的folder项目

第一次在这个论坛上写博客,而且开始写博客的时间并不长,所以如果我的代码难懂的话也请大家多多包涵,废话不多说,进入正题了。

目前的我还只是一个大四的学生,在公司实习已经两个月了,当然,这并不是我的第一个项目,上个月是仅仅是用c#用三层架构写的,感觉才过了一个月,我已经把c#的基础打好了,以前总以为自己已经学到很多了,有足够的能力去胜任一份工作了,在工作了一个月之后才发现原来还远远不够。前话已经说了,现在我来说说我的项目,因为这里的网络并不是太好,我就不截图演示了,只是放代码分析就好了

1、UI层(xmal)

相信有silverlight基础的你都不难明白,silverlight+wcf做的项目,UI层是Windows的,其他是web的,所以silverlight的程序是比web程序灵活的

<UserControl 
    xmlns:sdk = "http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  
    x:Class = "HuaweiSoftware.Folder.FolderUI.MainPage"
    xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    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"
    xmlns:controls = "clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
    xmlns:common="clr-namespace:System.Windows;assembly=System.Windows.Controls"
    mc:Ignorable = "d"
    d:DesignHeight = "1000" d:DesignWidth="1000">

    <Grid x:Name="LayoutRoot" Background="#46461F">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" HorizontalAlignment="Center">
            <Grid Width="1000">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="800"></ColumnDefinition>
                    <ColumnDefinition Width="50"></ColumnDefinition>
                    <ColumnDefinition Width="50"></ColumnDefinition>
                    <ColumnDefinition Width="50"></ColumnDefinition>
                    <ColumnDefinition Width="50"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Border Grid.Column="0" BorderThickness="1.5" BorderBrush="White" CornerRadius="6" Background="White" Height="38" Margin="2,1,2,1">
                    <TextBox x:Name="txtPath" Margin="2,2,2,2" BorderThickness="0" FontSize="13"/>
                </Border>
                <Border Grid.Column="1" Margin="1">
                    <Button x:Name="btnSave" Content="保存" FontSize="13" Click="btnSave_Click" Margin="0,0,0,0"></Button>
                </Border>
                <Border Grid.Column="2" Margin="1">
                    <Button x:Name="btnLoad" Content="加载" FontSize="13" Click="btnLoad_Click" Margin="0,0,0,0"></Button>
                </Border>
                <Border Grid.Column="3" Margin="1">
                    <Button x:Name="btnSearch" Content="查找" FontSize="13" Click="btnSearch_Click" Margin="0,0,0,0"></Button>
                </Border>
                <Border Grid.Column="4" Margin="1">
                    <Button x:Name="btnADD" Content="增加" FontSize="13" Click="btnADD_Click" Margin="0,0,0,0"></Button>
                </Border>
            </Grid>
        </Grid>
        
        <Grid Grid.Row="1" HorizontalAlignment="Center" Margin="2">
            <Grid Width="1000">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="340"></ColumnDefinition>
                    <ColumnDefinition Width="*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Border Grid.Column="0" Margin="1">
                    <controls:TreeView x:Name="directoryTree" BorderThickness="0" Loaded="btnLoad_Click" SelectedItemChanged="myTree_SelectedItemChanged" Margin="1,0,0,0">                        
                    </controls:TreeView>
                </Border>
                <Border Grid.Column="1" Margin="1">
                    <sdk:DataGrid x:Name="dgFile" Margin="1,0,0,1" AutoGenerateColumns="False">
                        <sdk:DataGrid.Columns>
                            <sdk:DataGridTextColumn Header="文件名" Width="160" Binding="{Binding Name}" />
                            <sdk:DataGridTextColumn Header="创建日期" Width="170" Binding="{Binding CreateDate}" />
                            <sdk:DataGridTextColumn Header="修改日期" Width="170" Binding="{Binding ModifyDate}" />
                            <sdk:DataGridTextColumn Header="文件类型" Width="90" Binding="{Binding Type}" />
                            <sdk:DataGridTextColumn Header="文件大小" Width="*" Binding="{Binding Size}" />
                        </sdk:DataGrid.Columns>
                    </sdk:DataGrid>
                </Border>
            </Grid>
        </Grid>
    </Grid>    
</UserControl>
我也是刚刚接触silverlight的,所以一开始理解那些库的使用方法的时候真的花了我不少时间,其实有一部分原因是我的c#的基础并不是特别扎实,所以在做这个的时候就感觉比较吃力,还好最后也是能理解出来,写出了这个简单的界面

2、.xmal.cs

这个文件算起来就像是web程序里的后台,但是这里的后台只是用来调用wcf服务的,并不能链接数据库对数据库进行操作

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.ServiceModel;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using HuaweiSoftware.Folder.FolderUI.FolderService;

namespace HuaweiSoftware.Folder.FolderUI
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 保存按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            string path = txtPath.Text;
            if (path != "")
            {
                int seq=0;
                ObservableCollection<Folders> allfolders = new ObservableCollection<Folders>();
                FolderWCFClient client = new FolderWCFClient();
                client.InsertDataCompleted += new EventHandler<InsertDataCompletedEventArgs>(client_InsertDataCompleted);
                client.InsertDataAsync(path, seq, allfolders);
            }
            else
            {
                HtmlPage.Window.Alert("没有输入任何路径!!");
            }
        }

        /// <summary>
        /// 完成插入数据的异步调用
        /// </summary>
        void client_InsertDataCompleted(object sender, InsertDataCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.Result)
                {
                    HtmlPage.Window.Alert("保存文件夹成功!");                    
                }
                else
                {
                    HtmlPage.Window.Alert("输入的路径不存在!!");                    
                }
                txtPath.Text = "";
            }
            else
            {
                HtmlPage.Window.Alert(e.Error.Message);
            }
        }       

        /// <summary>
        /// 加载按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            directoryTree.Items.Clear();
            dgFile.ItemsSource = null;
            FolderWCFClient client = new FolderWCFClient();
            client.GetFoldersCompleted += new EventHandler<GetFoldersCompletedEventArgs>(client_GetFoldersCompleted);
            client.GetFoldersAsync();
        }

        /// <summary>
        /// 完成获取数据集合的异步调用
        /// </summary>
        void client_GetFoldersCompleted(object sender, GetFoldersCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                
                ObservableCollection<Folders> treeFolder = e.Result;                                
                FolderTree tree = new FolderTree();
                tree.AddTreeNode(directoryTree, treeFolder, null, null);
            }
            else
            {
                HtmlPage.Window.Alert(e.Error.Message);
            }
        }        

        /// <summary>
        /// treeview选中节点变化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void myTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (directoryTree.Items.Count != 0)
            {
                TreeViewItem treeNode = (TreeViewItem)directoryTree.SelectedItem;
                ObservableCollection<int> itemsID = new ObservableCollection<int>();
                foreach (TreeViewItem node in treeNode.Items)
                {
                    Folders nodeFolder = (Folders)node.DataContext;
                    itemsID.Add(nodeFolder.ID);
                }
                FolderWCFClient client = new FolderWCFClient();
                client.GetFilesCompleted += new EventHandler<GetFilesCompletedEventArgs>(client_GetFilesCompleted);
                client.GetFilesAsync(itemsID);
            }            
        }

        /// <summary>
        /// 完成获取选中节点的子节点集合的异步调用
        /// </summary>        
        void client_GetFilesCompleted(object sender, GetFilesCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                dgFile.ItemsSource = e.Result;                
            }
            else
            {
                
            }
        }

后台的理解我也是花了一个星期的时间才能自己调用wcf服务而非直接抄网上的代码,刚看的时候简直就是在看天书,懵懵懂懂的

3、wcf服务

这个算是我整个项目里最难的一部分了,因为要对数据库进行操作,而我对接口和实现又没有一点点概念,当时就只是跟网上的那些代码一样,什么都在.svc.cs里写了,小小的一个项目我就用了两百行代码,确实繁琐,导致后来出现了一个bug,就是那个“远程服务器发生错误:not found!”,这个bug我在网上找了好几天都调不了,根本不知道是什么错,连fiddler都用上了但还是不知道,然后无意中在重构代码的时候解决了,原来是因为我把代码都放到了.svc.cs这个文件里,所以程序出错了,以下是我的代码

这个是实现的代码:

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Web.UI.WebControls;

using Microsoft.Win32;
using HuaweiSoftware.Folder.FolderDAL;
using HuaweiSoftware.Folder.FolderEntity;


namespace HuaweiSoftware.Folder.FolderWeb
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“FolderWCF”。
    // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 FolderWCF.svc 或 FolderWCF.svc.cs,然后开始调试。
    public class FolderWCF : IFolderWCF
    {
        public void DoWork()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <param name="seq"></param>
        /// <param name="allFolders"></param>
        /// <returns></returns>
        public bool InsertData(string path, ref int seq, ref List<Folders> allFolders)
        {
            if(Directory.Exists(path))
            {
                FolderDal dal = new FolderDal();
                //每次添加数据前都删除数据
                dal.ClearData();
                GetData getData = new GetData();
                List<Folders> listFolders = getData.GetSubFolders(path, ref seq, ref allFolders);
                getData.SaveFolder(listFolders, -1);

                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 获取数据库的数据表到list中
        /// </summary>
        /// <returns></returns>
        public List<Folders> GetFolders()
        {
            FolderDal dal = new FolderDal();
            List<Folders> listTbl = dal.GetListTbl();
            List<Folders> allFolders = new List<Folders>();            
            try
            {
                foreach (Folders folders in listTbl)
                {
                    Folders folder = new Folders();
                    folder.ID = folders.ID;
                    folder.Level = folders.Level;
                    folder.Seq = folders.Seq;
                    folder.Name = folders.Name;
                    folder.CreateDate = folders.CreateDate;
                    folder.ModifyDate = folders.ModifyDate;
                    folder.Type = folders.Type;
                    folder.Size = folders.Size;
                    allFolders.Add(folder);
                }                

                return allFolders;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }       

        /// <summary>
        /// 获取treeview选中节点下的文件集合
        /// </summary>
        /// <returns></returns>
        public List<Folders> GetFiles(List<int> listID)
        {            
            try
            {
                FolderDal dal = new FolderDal();
                List<Folders> lisTbl = dal.GetListTbl();
                List<Folders> fileFolder = new List<Folders>();
                foreach (int id in listID)
                {
                    foreach (Folders folder in lisTbl)
                    {
                        if (folder.ID == id)
                        {
                            fileFolder.Add(folder);
                        }
                    }
                }                

                return fileFolder;
            }
            catch(Exception ex)
            {
                throw ex;
            }            
        }
这个是接口的代码:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

using HuaweiSoftware.Folder.FolderEntity;

namespace HuaweiSoftware.Folder.FolderWeb
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IFolderWCF”。
    [ServiceContract]
    public interface IFolderWCF
    {
        [OperationContract]
        void DoWork();

        [OperationContract]
        bool InsertData(string path, ref int seq, ref List<Folders> allFolders);

        [OperationContract]
        List<Folders> GetFolders();

        [OperationContract]
        List<Folders> GetFiles(List<int> listID);

        [OperationContract]
        List<Folders> SearchFolder(string name);
    }
}

当然,我刚刚已经说了,我是把所有的代码都放到这里才会出错,所以我在重构代码的时候把那些可以简化的代码都放在了一个新建的类中

using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using HuaweiSoftware.Folder.FolderDAL;
using HuaweiSoftware.Folder.FolderEntity;

namespace HuaweiSoftware.Folder.FolderWeb
{
    public class GetData
    {
        //根节点的级数
        int dValue = 0;

        /// <summary>
        /// 通过路径获取文件并存入list集合中
        /// </summary>
        /// <param name="path">文件路径</param>
        /// <param name="seq">存入顺序</param>
        /// <param name="allFolders">list集合</param>
        /// <returns></returns>
        public List<Folders> GetSubFolders(string path, ref int seq, ref List<Folders> allFolders)
        {            
            try
            {
                //保存根节点
                if (allFolders.Count <= 0)
                {
                    Folders rootFolder = new Folders();
                    string[] pathStr = path.Split('\\');
                    dValue = pathStr.Length;                    
                    DirectoryInfo rootInfo = new DirectoryInfo(path);
                    rootFolder.Level = pathStr.Length - dValue;
                    rootFolder.Seq = seq;
                    seq++;
                    rootFolder.Name = rootInfo.Name;
                    rootFolder.Type = "文件夹";
                    rootFolder.CreateDate = rootInfo.CreationTime;
                    rootFolder.ModifyDate = DateTime.Now;
                    allFolders.Add(rootFolder);
                    GetSubFolders(path, ref seq, ref allFolders);
                }
                else
                {
                    string[] folders = Directory.GetDirectories(path);
                    string[] files = Directory.GetFiles(path);
                    if ((null != folders) && (folders.Length > 0))
                    {
                        foreach (string folder in folders)
                        {
                            Folders folderEntity = new Folders();
                            string[] folderStr = folder.Split('\\');
                            DirectoryInfo folderInfo = new DirectoryInfo(folder);
                            folderEntity.Level = folderStr.Length - dValue;
                            folderEntity.Seq = seq;
                            seq++;
                            folderEntity.Name = folderInfo.Name;
                            folderEntity.Type = "文件夹";
                            folderEntity.CreateDate = folderInfo.CreationTime;
                            folderEntity.ModifyDate = DateTime.Now;
                            allFolders.Add(folderEntity);
                            GetSubFolders(folder, ref seq, ref allFolders);
                        }
                    }
                    if ((null != files) && (files.Length > 0))
                    {
                        foreach (string file in files)
                        {
                            Folders fileEntity = new Folders();
                            string[] fileStr = file.Split('\\');
                            FileInfo fileInfo = new FileInfo(file);
                            fileEntity.Level = fileStr.Length - dValue;
                            fileEntity.Seq = seq;
                            seq++;
                            fileEntity.Name = fileInfo.Name;
                            fileEntity.Type = "文件";
                            fileEntity.CreateDate = fileInfo.CreationTime;
                            fileEntity.ModifyDate = DateTime.Now;
                            allFolders.Add(fileEntity);
                        }
                    }
                }

                return allFolders;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }        

        /// <summary>
        /// 保存文件到数据库
        /// </summary>
        /// <param name="allFolders">需要保存的文件的list集合</param>
        /// <returns></returns>
        public void SaveFolder(List<Folders> allFolders, int level)
        {
            FolderDal dal = new FolderDal();
            try
            {
                List<Folders> filterList = allFolders.FindAll(delegate(Folders folders)
                {
                    return folders.Level == level + 1;
                });
                if (filterList.Count > 0)
                {
                    dal.InsertData(filterList);
                    SaveFolder(allFolders, level + 1);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
到这里为止,我的项目最重要的部分基本已经结束了,接下来就只剩下数据层和实体层了

4、数据层(FolderDAL)

这个我就不多说了,我只是建了两个类,一个是负责操作数据库的,一个是负责传SQL语句的

DBHelper.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace HuaweiSoftware.Folder.FolderDAL
{
    public class DBHelper
    {
        public static string ConnectionString = ConfigurationManager.ConnectionStrings["conStr"].ToString();

        /// <summary>
        /// 获取数据表并存入datatable中
        /// </summary>
        /// <param name="m_Connection">创建的链接</param>
        /// <param name="cmdText">需要执行的SQL语句</param>
        /// <returns>执行SQL语句得到的datatable</returns>
        public static DataTable ExecuteDataTable(SqlConnection m_Connection, string cmdText)
        {
            using (SqlCommand cmd = m_Connection.CreateCommand())
            {
                cmd.CommandText = cmdText;
                using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
                {
                    DataTable dt = new DataTable();
                    adapter.Fill(dt);

                    return dt;
                }
            }
        }

        /// <summary>
        /// 执行由cmdText传入的SQL语句
        /// </summary>
        /// <param name="m_Connection">创建的链接</param>
        /// <param name="cmdText">需要执行的SQL语句</param>
        /// <param name="parameters">SQL语句中的参数</param>
        /// <returns>执行完SQL语句后返回的值</returns>
        public static int ExecuteNonQuery(SqlConnection m_Connection, string cmdText, params SqlParameter[] parameters)
        {
            using (SqlCommand cmd = m_Connection.CreateCommand())
            {
                cmd.CommandText = cmdText;
                cmd.Parameters.AddRange(parameters);
                m_Connection.Open();

                return cmd.ExecuteNonQuery();
            }
        }

        /// <summary>
        /// 执行SQL语句
        /// </summary>
        /// <param name="m_Connection"></param>
        /// <param name="cmdText"></param>
        /// <returns></returns>
        public static int ExecuteNonQuery(SqlConnection m_Connection, string cmdText)
        {
            using (SqlCommand cmd = m_Connection.CreateCommand())
            {
                cmd.CommandText = cmdText;
                m_Connection.Open();

                return cmd.ExecuteNonQuery();
            }
        }
    }
}
FolderDal.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using HuaweiSoftware.Folder.FolderEntity;

namespace HuaweiSoftware.Folder.FolderDAL
{
    public class FolderDal
    {
        public SqlConnection m_Connection;

        public FolderDal()
        {
            m_Connection = new SqlConnection(DBHelper.ConnectionString);
        }

        /// <summary>
        /// 保存文件目录数据表
        /// </summary>
        /// <param name="folders"></param>
        public void InsertData(List<Folders> folders)
        {            
            string sqlString = "INSERT INTO Folder VALUES(@Level,@Seq,@Name,@CreateDate,@ModifyDate,@Type,@Size)";
            foreach (Folders folder in folders)
            {
                SqlParameter[] pars = new SqlParameter[]
                {
                    new SqlParameter("@Level",SqlDbType.Int){ Value = folder.Level },
                    new SqlParameter("@Seq",SqlDbType.Int){ Value = folder.Seq },
                    new SqlParameter("@Name",SqlDbType.NVarChar,50){ Value = folder.Name },
                    new SqlParameter("@CreateDate",SqlDbType.DateTime){ Value = folder.CreateDate },
                    new SqlParameter("@ModifyDate",SqlDbType.DateTime){ Value = folder.ModifyDate },
                    new SqlParameter("@Type",SqlDbType.NVarChar,50){ Value = folder.Type },
                    new SqlParameter("@Size",SqlDbType.Int){ Value = folder.Size }
                };
                DBHelper.ExecuteNonQuery(m_Connection, sqlString, pars);
                m_Connection.Close();
            }            
        }

        /// <summary>
        /// 获取数据表到list集合
        /// </summary>
        /// <returns></returns>
        public List<Folders> GetListTbl()
        {
            string sqlString = "SELECT * FROM Folder ORDER BY Seq";
            DataTable table = DBHelper.ExecuteDataTable(m_Connection, sqlString);
            List<Folders> listTbl = new List<Folders>();
            foreach (DataRow row in table.Rows)
            {
                Folders folders = new Folders();
                folders.ID = (int)row["ID"];
                folders.Level = (int)row["Level"];
                folders.Seq = (int)row["Seq"];
                folders.Name = (string)row["Name"];
                folders.CreateDate = (DateTime)row["CreateDate"];
                folders.ModifyDate = (DateTime)row["ModifyDate"];
                folders.Type = (string)row["Type"];
                folders.Size = (int)row["Size"];
                listTbl.Add(folders);
            }

            return listTbl;
        }

        /// <summary>
        /// 清除数据表
        /// </summary>
        public void ClearData()
        {
            string sqlString = "TRUNCATE TABLE Folder";
            DBHelper.ExecuteNonQuery(m_Connection, sqlString);
            m_Connection.Close();
        }        
    }
}

5、实体层

Folders.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace HuaweiSoftware.Folder.FolderEntity
{
    public class Folders
    {
        private int m_ID;
        private int m_Level;
        private int m_Seq;
        private string m_Name;
        private DateTime m_CreateDate;
        private DateTime m_ModifyDate;
        private string m_Type;
        private int m_Size;

        /// <summary>
        /// 自增ID
        /// </summary>
        public int ID
        {
            get
            {
                return m_ID;
            }
            set
            {
                m_ID = value;
            }
        }

        /// <summary>
        /// 级数
        /// </summary>
        public int Level
        {
            get
            {
                return m_Level;
            }
            set
            {
                m_Level = value;
            }
        }

        /// <summary>
        /// 顺序
        /// </summary>
        public int Seq
        {
            get
            {
                return m_Seq;
            }
            set
            {
                m_Seq = value;
            }
        }

        /// <summary>
        /// 文件名
        /// </summary>
        public string Name
        {
            get
            {
                return m_Name;
            }
            set
            {
                m_Name = value;
            }
        }

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateDate
        {
            get
            {
                return m_CreateDate;
            }
            set
            {
                m_CreateDate = value;
            }
        }

        /// <summary>
        /// 修改时间
        /// </summary>
        public DateTime ModifyDate
        {
            get
            {
                return m_ModifyDate;
            }
            set
            {
                m_ModifyDate = value;
            }
        }

        /// <summary>
        /// 文件类型
        /// </summary>
        public string Type
        {
            get
            {
                return m_Type;
            }
            set
            {
                m_Type = value;
            }
        }

        /// <summary>
        /// 文件大小
        /// </summary>
        public int Size
        {
            get
            {
                return m_Size;
            }
            set
            {
                m_Size = value;
            }
        }
    }
}
好了,记录到这里基本上整个项目都结束了,我也只是小白一个,我写这些也仅仅是记录我自己的学习状态,如果大家觉得不好勿喷,在学习中进步,我会更加努力去改善自己的知识,谢谢~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值