C# Task用法
1、Task的优势
ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便。比如:
◆ ThreadPool不支持线程的取消、完成、失败通知等交互性操作;
◆ ThreadPool不支持线程执行的先后次序;
以往,如果开发者要实现上述功能,需要完成很多额外的工作,现在,FCL中提供了一个功能更强大的概念:Task。Task在线程池的基础上进行了优化,并提供了更多的API。在FCL4.0中,如果我们要编写多线程程序,Task显然已经优于传统的方式。
以下是一个简单的任务示例:
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Task t = new Task(() =>
{
Console.WriteLine("任务开始工作……");
//模拟工作过程
Thread.Sleep();
});
t.Start();
t.ContinueWith((task) =>
{
Console.WriteLine("任务完成,完成时候的状态为:");
Console.WriteLine("IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
});
Console.ReadKey();
}
}
}
Program
2、Task的用法
2.1、创建任务
无返回值的方式
方式1:
var t1 = new Task(() => TaskMethod("Task 1"));
t1.Start();
Task.WaitAll(t1);//等待所有任务结束
注:
任务的状态:
Start之前为:Created
Start之后为:WaitingToRun
方式2:
Task.Run(() => TaskMethod("Task 2"));
方式3:
Task.Factory.StartNew(() => TaskMethod("Task 3")); 直接异步的方法
或者
var t3=Task.Factory.StartNew(() => TaskMethod("Task 3"));
Task.WaitAll(t3);//等待所有任务结束
注:
任务的状态:
Start之前为:Running
Start之后为:Running
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var t1 = new Task(() => TaskMethod("Task 1"));
var t2 = new Task(() => TaskMethod("Task 2"));
t2.Start();
t1.Start();
Task.WaitAll(t1, t2);
Task.Run(() => TaskMethod("Task 3"));
Task.Factory.StartNew(() => TaskMethod("Task 4"));
//标记为长时间运行任务,则任务不会使用线程池,而在单独的线程中运行。
Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning); #region 常规的使用方式
Console.WriteLine("主线程执行业务处理.");
//创建任务
Task task = new Task(() =>
{
Console.WriteLine("使用System.Threading.Tasks.Task执行异步操作.");
for (int i = ; i < ; i++)
{
Console.WriteLine(i);
}
});
//启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
task.Start();
Console.WriteLine("主线程执行其他处理");
task.Wait();
#endregion Thread.Sleep(TimeSpan.FromSeconds());
Console.ReadLine();
} static void TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
}
}
Program
async/await的实现方式:
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
async static void AsyncFunction()
{
await Task.Delay();
Console.WriteLine("使用System.Threading.Tasks.Task执行异步操作.");
for (int i = ; i < ; i++)
{
Console.WriteLine(string.Format("AsyncFunction:i={0}", i));
}
} public static void Main()
{
Console.WriteLine("主线程执行业务处理.");
AsyncFunction();
Console.WriteLine("主线程执行其他处理");
for (int i = ; i < ; i++)
{
Console.WriteLine(string.Format("Main:i={0}", i));
}
Console.ReadLine();
}
}
}
Program
带返回值的方式
方式4:
Task<int> task = CreateTask("Task 1");
task.Start();
int result = task.Result;
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static Task<int> CreateTask(string name)
{
return new Task<int>(() => TaskMethod(name));
} static void Main(string[] args)
{
TaskMethod("Main Thread Task");
Task<int> task = CreateTask("Task 1");
task.Start();
int result = task.Result;
Console.WriteLine("Task 1 Result is: {0}", result); task = CreateTask("Task 2");
//该任务会运行在主线程中
task.RunSynchronously();
result = task.Result;
Console.WriteLine("Task 2 Result is: {0}", result); task = CreateTask("Task 3");
Console.WriteLine(task.Status);
task.Start(); while (!task.IsCompleted)
{
Console.WriteLine(task.Status);
Thread.Sleep(TimeSpan.FromSeconds(0.5));
} Console.WriteLine(task.Status);
result = task.Result;
Console.WriteLine("Task 3 Result is: {0}", result); #region 常规使用方式
//创建任务
Task<int> getsumtask = new Task<int>(() => Getsum());
//启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
getsumtask.Start();
Console.WriteLine("主线程执行其他处理");
//等待任务的完成执行过程。
getsumtask.Wait();
//获得任务的执行结果
Console.WriteLine("任务执行结果:{0}", getsumtask.Result.ToString());
#endregion
} static int TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds());
return ;
} static int Getsum()
{
int sum = ;
Console.WriteLine("使用Task执行异步操作.");
for (int i = ; i < ; i++)
{
sum += i;
}
return sum;
}
}
}
Program
async/await的实现:
using System;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
public static void Main()
{
var ret1 = AsyncGetsum();
Console.WriteLine("主线程执行其他处理");
for (int i = ; i <= ; i++)
Console.WriteLine("Call Main()");
int result = ret1.Result; //阻塞主线程
Console.WriteLine("任务执行结果:{0}", result);
} async static Task<int> AsyncGetsum()
{
await Task.Delay();
int sum = ;
Console.WriteLine("使用Task执行异步操作.");
for (int i = ; i < ; i++)
{
sum += i;
}
return sum;
}
}
}
Program
2.2、组合任务.ContinueWith
简单Demo:
using System;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
public static void Main()
{
//创建一个任务
Task<int> task = new Task<int>(() =>
{
int sum = ;
Console.WriteLine("使用Task执行异步操作.");
for (int i = ; i < ; i++)
{
sum += i;
}
return sum;
});
//启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
task.Start();
Console.WriteLine("主线程执行其他处理");
//任务完成时执行处理。
Task cwt = task.ContinueWith(t =>
{
Console.WriteLine("任务完成后的执行结果:{0}", t.Result.ToString());
});
task.Wait();
cwt.Wait();
}
}
}
Program
任务的串行:
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
ConcurrentStack<int> stack = new ConcurrentStack<int>(); //t1先串行
var t1 = Task.Factory.StartNew(() =>
{
stack.Push();
stack.Push();
}); //t2,t3并行执行
var t2 = t1.ContinueWith(t =>
{
int result;
stack.TryPop(out result);
Console.WriteLine("Task t2 result={0},Thread id {1}", result, Thread.CurrentThread.ManagedThreadId);
}); //t2,t3并行执行
var t3 = t1.ContinueWith(t =>
{
int result;
stack.TryPop(out result);
Console.WriteLine("Task t3 result={0},Thread id {1}", result, Thread.CurrentThread.ManagedThreadId);
}); //等待t2和t3执行完
Task.WaitAll(t2, t3); //t7串行执行
var t4 = Task.Factory.StartNew(() =>
{
Console.WriteLine("当前集合元素个数:{0},Thread id {1}", stack.Count, Thread.CurrentThread.ManagedThreadId);
});
t4.Wait();
}
}
}
Program
子任务:
using System;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
public static void Main()
{
Task<string[]> parent = new Task<string[]>(state =>
{
Console.WriteLine(state);
string[] result = new string[];
//创建并启动子任务
new Task(() => { result[] = "我是子任务1。"; }, TaskCreationOptions.AttachedToParent).Start();
new Task(() => { result[] = "我是子任务2。"; }, TaskCreationOptions.AttachedToParent).Start();
return result;
}, "我是父任务,并在我的处理过程中创建多个子任务,所有子任务完成以后我才会结束执行。");
//任务处理完成后执行的操作
parent.ContinueWith(t =>
{
Array.ForEach(t.Result, r => Console.WriteLine(r));
});
//启动父任务
parent.Start();
//等待任务结束 Wait只能等待父线程结束,没办法等到父线程的ContinueWith结束
//parent.Wait();
Console.ReadLine(); }
}
}
Program
动态并行(TaskCreationOptions.AttachedToParent) 父任务等待所有子任务完成后 整个任务才算完成
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Node
{
public Node Left { get; set; }
public Node Right { get; set; }
public string Text { get; set; }
} class Program
{
static Node GetNode()
{
Node root = new Node
{
Left = new Node
{
Left = new Node
{
Text = "L-L"
},
Right = new Node
{
Text = "L-R"
},
Text = "L"
},
Right = new Node
{
Left = new Node
{
Text = "R-L"
},
Right = new Node
{
Text = "R-R"
},
Text = "R"
},
Text = "Root"
};
return root;
} static void Main(string[] args)
{
Node root = GetNode();
DisplayTree(root);
} static void DisplayTree(Node root)
{
var task = Task.Factory.StartNew(() => DisplayNode(root),
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default);
task.Wait();
} static void DisplayNode(Node current)
{ if (current.Left != null)
Task.Factory.StartNew(() => DisplayNode(current.Left),
CancellationToken.None,
TaskCreationOptions.AttachedToParent,
TaskScheduler.Default);
if (current.Right != null)
Task.Factory.StartNew(() => DisplayNode(current.Right),
CancellationToken.None,
TaskCreationOptions.AttachedToParent,
TaskScheduler.Default);
Console.WriteLine("当前节点的值为{0};处理的ThreadId={1}", current.Text, Thread.CurrentThread.ManagedThreadId);
}
}
}
Program
2.3、取消任务 CancellationTokenSource
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
private static int TaskMethod(string name, int seconds, CancellationToken token)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
for (int i = ; i < seconds; i++)
{
Thread.Sleep(TimeSpan.FromSeconds());
if (token.IsCancellationRequested) return -;
}
return * seconds;
} private static void Main(string[] args)
{
var cts = new CancellationTokenSource();
var longTask = new Task<int>(() => TaskMethod("Task 1", , cts.Token), cts.Token);
Console.WriteLine(longTask.Status);
cts.Cancel();
Console.WriteLine(longTask.Status);
Console.WriteLine("First task has been cancelled before execution");
cts = new CancellationTokenSource();
longTask = new Task<int>(() => TaskMethod("Task 2", , cts.Token), cts.Token);
longTask.Start();
for (int i = ; i < ; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine(longTask.Status);
}
cts.Cancel();
for (int i = ; i < ; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine(longTask.Status);
} Console.WriteLine("A task has been completed with result {0}.", longTask.Result);
}
}
}
Program
2.4、处理任务中的异常
单个任务:
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static int TaskMethod(string name, int seconds)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
throw new Exception("Boom!");
return * seconds;
} static void Main(string[] args)
{
try
{
Task<int> task = Task.Run(() => TaskMethod("Task 2", ));
int result = task.GetAwaiter().GetResult();
Console.WriteLine("Result: {0}", result);
}
catch (Exception ex)
{
Console.WriteLine("Task 2 Exception caught: {0}", ex.Message);
}
Console.WriteLine("----------------------------------------------");
Console.WriteLine();
}
}
}
Program
多个任务:
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static int TaskMethod(string name, int seconds)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
throw new Exception(string.Format("Task {0} Boom!", name));
return * seconds;
} public static void Main(string[] args)
{
try
{
var t1 = new Task<int>(() => TaskMethod("Task 3", ));
var t2 = new Task<int>(() => TaskMethod("Task 4", ));
var complexTask = Task.WhenAll(t1, t2);
var exceptionHandler = complexTask.ContinueWith(t =>
Console.WriteLine("Result: {0}", t.Result),
TaskContinuationOptions.OnlyOnFaulted
);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
}
catch (AggregateException ex)
{
ex.Handle(exception =>
{
Console.WriteLine(exception.Message);
return true;
});
}
}
}
}
Program
async/await的方式:
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static async Task ThrowNotImplementedExceptionAsync()
{
throw new NotImplementedException();
} static async Task ThrowInvalidOperationExceptionAsync()
{
throw new InvalidOperationException();
} static async Task Normal()
{
await Fun();
} static Task Fun()
{
return Task.Run(() =>
{
for (int i = ; i <= ; i++)
{
Console.WriteLine("i={0}", i);
Thread.Sleep();
}
});
} static async Task ObserveOneExceptionAsync()
{
var task1 = ThrowNotImplementedExceptionAsync();
var task2 = ThrowInvalidOperationExceptionAsync();
var task3 = Normal(); try
{
//异步的方式
Task allTasks = Task.WhenAll(task1, task2, task3);
await allTasks;
//同步的方式
//Task.WaitAll(task1, task2, task3);
}
catch (NotImplementedException ex)
{
Console.WriteLine("task1 任务报错!");
}
catch (InvalidOperationException ex)
{
Console.WriteLine("task2 任务报错!");
}
catch (Exception ex)
{
Console.WriteLine("任务报错!");
} } public static void Main()
{
Task task = ObserveOneExceptionAsync();
Console.WriteLine("主线程继续运行........");
task.Wait();
}
}
}
Program
2.5、Task.FromResult的应用
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static IDictionary<string, string> cache = new Dictionary<string, string>()
{
{"","A"},
{"","B"},
{"","C"},
{"","D"},
{"","E"},
{"","F"},
}; public static void Main()
{
Task<string> task = GetValueFromCache("");
Console.WriteLine("主程序继续执行。。。。");
string result = task.Result;
Console.WriteLine("result={0}", result); } private static Task<string> GetValueFromCache(string key)
{
Console.WriteLine("GetValueFromCache开始执行。。。。");
string result = string.Empty;
//Task.Delay(5000);
Thread.Sleep();
Console.WriteLine("GetValueFromCache继续执行。。。。");
if (cache.TryGetValue(key, out result))
{
return Task.FromResult(result);
}
return Task.FromResult("");
} }
}
Program
2.6、使用IProgress实现异步编程的进程通知
IProgress<in T>只提供了一个方法void Report(T value),通过Report方法把一个T类型的值报告给IProgress,然后IProgress<in T>的实现类Progress<in T>的构造函数接收类型为Action<T>的形参,通过这个委托让进度显示在UI界面中。
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
static void DoProcessing(IProgress<int> progress)
{
for (int i = ; i <= ; ++i)
{
Thread.Sleep();
if (progress != null)
{
progress.Report(i);
}
}
} static async Task Display()
{
//当前线程
var progress = new Progress<int>(percent =>
{
Console.Clear();
Console.Write("{0}%", percent);
});
//线程池线程
await Task.Run(() => DoProcessing(progress));
Console.WriteLine("");
Console.WriteLine("结束");
} public static void Main()
{
Task task = Display();
task.Wait();
}
}
}
Program
2.7、Factory.FromAsync的应用 (简APM模式(委托)转换为任务)(BeginXXX和EndXXX)
带回调方式的
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
private delegate string AsynchronousTask(string threadName); private static string Test(string threadName)
{
Console.WriteLine("Starting...");
Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds());
Thread.CurrentThread.Name = threadName;
return string.Format("Thread name: {0}", Thread.CurrentThread.Name);
} private static void Callback(IAsyncResult ar)
{
Console.WriteLine("Starting a callback...");
Console.WriteLine("State passed to a callbak: {0}", ar.AsyncState);
Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
Console.WriteLine("Thread pool worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
} //执行的流程是 先执行Test--->Callback--->task.ContinueWith
static void Main(string[] args)
{
AsynchronousTask d = Test;
Console.WriteLine("Option 1");
Task<string> task = Task<string>.Factory.FromAsync(
d.BeginInvoke("AsyncTaskThread", Callback, "a delegate asynchronous call"), d.EndInvoke); task.ContinueWith(t => Console.WriteLine("Callback is finished, now running a continuation! Result: {0}",
t.Result)); while (!task.IsCompleted)
{
Console.WriteLine(task.Status);
Thread.Sleep(TimeSpan.FromSeconds(0.5));
}
Console.WriteLine(task.Status); }
}
}
Program
不带回调方式的
using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp1
{
class Program
{
private delegate string AsynchronousTask(string threadName); private static string Test(string threadName)
{
Console.WriteLine("Starting...");
Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds());
Thread.CurrentThread.Name = threadName;
return string.Format("Thread name: {0}", Thread.CurrentThread.Name);
} //执行的流程是 先执行Test--->task.ContinueWith
static void Main(string[] args)
{
AsynchronousTask d = Test;
Task<string> task = Task<string>.Factory.FromAsync(
d.BeginInvoke, d.EndInvoke, "AsyncTaskThread", "a delegate asynchronous call");
task.ContinueWith(t => Console.WriteLine("Task is completed, now running a continuation! Result: {0}",
t.Result));
while (!task.IsCompleted)
{
Console.WriteLine(task.Status);
Thread.Sleep(TimeSpan.FromSeconds(0.5));
}
Console.WriteLine(task.Status); }
}
}
Program
C# Task用法的更多相关文章
- C# Task 用法
C# Task 的用法 其实Task跟线程池ThreadPool的功能类似,不过写起来更为简单,直观.代码更简洁了,使用Task来进行操作.可以跟线程一样可以轻松的对执行的方法进行控制. 顺便提一下, ...
- 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程
反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) 背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...
- SSIS Execute SQL Task 用法
Execute Sql Task组件是一个非常有用的Control Flow Task,可以直接执行SQL语句,例如,可以执行数据更新命令(update,delete,insert),也可以执行sel ...
- verilog之task用法实例
该用法的代码源自夏宇闻老师的教材. 源代码: module traffic_lights; reg clock, red, amber, green; , off = , red_tics = , a ...
- Task用法(2)-任务等待wait
1.Wait 用法 默认情况下,Task 是有线程池中的异步线程执行,是否执行完成,可以通过Task的的属性IsCompleted 来判断, 如果想在子线程工作完成之后,在进行后续主线程工作可以 ...
- verilog中的task用法
任务就是一段封装在“task-endtask”之间的程序.任务是通过调用来执行的,而且只有在调用时才执行,如果定义了任务,但是在整个过程中都没有调用它,那么这个任务是不会执行的.调用某个任务时可能需要 ...
- verilog 中task用法
1.任务定义 任务定义的形式如下: task task_id; [declaration] procedural_statement endtask 其中,关键词 task ...
- Task用法(1)-启动方法
第一.基本使用 Thread,ThreadPool,Task的区别 Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread ...
- C# 基础 之:Task 用法
参考来源:https://www.cnblogs.com/zhaoshujie/p/11082753.html 他介绍的可以说是非常详细,附带Demo例子讲解 1.入门 Task看起来像一个Threa ...
随机推荐
- c语言宏开关 使用
/* * 宏的写法,宏的作用域,当前位置开始到大括号结束,如果没有大括号,到文件结尾. */ #include <stdio.h> //#define HELLO int main(int ...
- shell中的常用条件判断
-e :该“文件名”是否存在.exit-d :该文件名是否为目录.dir-f :该文件名是否为普通文件.file -b:该文件是否为块文件.block -r :该文件是否具有可读属性 read-w ...
- 程序员基层知识程序与cpu【更新1】
我是一个小白,但我通过学习我慢慢的懂了一些事.分享出来有错误的望大咖指导. 我们要很明确的明白我们学的是编程而不是编程语言,编程语言只是工具用来方便我们做很多编程有关的事. 首先我在学习的过程中,第一 ...
- Android开发者的Anko使用指南(一)之Intent
使用Anko Intent帮助器可以添加如下依赖 dependencies { compile "org.jetbrains.anko:anko-commons:$anko_version& ...
- 查看 Oracle 数据库锁和解锁的方法
-- 查看数据库锁明细 select a.sid, b.serial#, b.username, b.osuser, b.machine, b.program, c.object_name,d.spi ...
- 【.NET Core项目实战-统一认证平台】第三章 网关篇-数据库存储配置(1)
[.NET Core项目实战-统一认证平台]开篇及目录索引 本篇将介绍如何扩展Ocelot中间件实现自定义网关,并使用2种不同数据库来演示Ocelot配置信息存储和动态更新功能,内容也是从实际设计出发 ...
- 笔记:安卓App消息处理机制
内容简述 类似Binder机制,MessageQueue.Looper也有底层的C++实现,涉及文件管道和驱动等. 以下仅从Java层的Looper.Handler和MessageQueue等相关类型 ...
- winform复制文件到指定目录
执行步骤 弹出选择对话框:var openFileDialog = new OpenFileDialog(); 设置选择内容,如所有图片:openFileDialog.Filter="图像文 ...
- 开源网盘云存储 Seafile
摘要: Seafile 是一款安全.高性能的开源网盘(云存储)软件.Seafile 提供了主流网盘(云盘)产品所具有的功能,包括文件同步.文件共享等.在此基础上,Seafile 还提供了高级的安全保护 ...
- 3D轮播图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...