一款开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control
甘特图在项目管理中非常重要,甘特图的思想比较简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间。它直观地表明任务计划在什么时候进行,及实际进展与计划要求的对比。管理者由此可便利地弄清一项任务(项目)还剩下哪些工作要做,并可评估工作进度。甘特图可以显示几个部门、机器或设备的运行和闲置情况。这表示了该系统的有关工作负荷状况,这样可使管理人员了解何种调整是恰当的。
由于项目需要,在网上找了很久,经过大量的对比和评估,发现一款真正开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control(http://ganttchart.codeplex.com/),效果图如下:
该款甘特图控件具有如下特征:
1、独立的时间单位数据结构规范;
2、支持单任务,分组任务,先例/依赖的任务,可以对任务进行拆分,并附加资源信息;
3、打印支持;
4、可对任务的计划和实际进行对比,以百分比进行进度跟踪;
5、在直接在甘特图上,对各种鼠标事件进行UI定制;
6、可以通过继承来修改默认的鼠标命令;
7、支持关键路径。
官方演示代码为:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 10 namespace Braincase.GanttChart 11 { 12 /// <summary> 13 /// An elaborate example on how the chart control might be used. 14 /// Start by collapsing all regions and then read the constructor. 15 /// Refer to IProjectManager interface for method description. 16 /// </summary> 17 public partial class ExampleFull : Form 18 { 19 OverlayPainter _mOverlay = new OverlayPainter(); 20 21 ProjectManager _mManager = null; 22 23 /// <summary> 24 /// Example starts here 25 /// </summary> 26 public ExampleFull() 27 { 28 InitializeComponent(); 29 30 // Create a Project and some Tasks 31 _mManager = new ProjectManager(); 32 var work = new MyTask(_mManager) { Name = "Prepare for Work" }; 33 var wake = new MyTask(_mManager) { Name = "Wake Up" }; 34 var teeth = new MyTask(_mManager) { Name = "Brush Teeth" }; 35 var shower = new MyTask(_mManager) { Name = "Shower" }; 36 var clothes = new MyTask(_mManager) { Name = "Change into New Clothes" }; 37 var hair = new MyTask(_mManager) { Name = "Blow My Hair" }; 38 var pack = new MyTask(_mManager) { Name = "Pack the Suitcase" }; 39 40 _mManager.Add(work); 41 _mManager.Add(wake); 42 _mManager.Add(teeth); 43 _mManager.Add(shower); 44 _mManager.Add(clothes); 45 _mManager.Add(hair); 46 _mManager.Add(pack); 47 48 // Create another 1000 tasks for stress testing 49 Random rand = new Random(); 50 for (int i = 0; i < 1000; i++) 51 { 52 var task = new MyTask(_mManager) { Name = string.Format("New Task {0}", i.ToString()) }; 53 _mManager.Add(task); 54 _mManager.SetStart(task, rand.Next(300)); 55 _mManager.SetDuration(task, rand.Next(50)); 56 } 57 58 // Set task durations, e.g. using ProjectManager methods 59 _mManager.SetDuration(wake, 3); 60 _mManager.SetDuration(teeth, 5); 61 _mManager.SetDuration(shower, 7); 62 _mManager.SetDuration(clothes, 4); 63 _mManager.SetDuration(hair, 3); 64 _mManager.SetDuration(pack, 5); 65 66 // demostrate splitting a task 67 _mManager.Split(pack, new MyTask(_mManager), new MyTask(_mManager), 2); 68 69 // Set task complete status, e.g. using newly created properties 70 wake.Complete = 0.9f; 71 teeth.Complete = 0.5f; 72 shower.Complete = 0.4f; 73 74 // Give the Tasks some organisation, setting group and precedents 75 _mManager.Group(work, wake); 76 _mManager.Group(work, teeth); 77 _mManager.Group(work, shower); 78 _mManager.Group(work, clothes); 79 _mManager.Group(work, hair); 80 _mManager.Group(work, pack); 81 _mManager.Relate(wake, teeth); 82 _mManager.Relate(wake, shower); 83 _mManager.Relate(shower, clothes); 84 _mManager.Relate(shower, hair); 85 _mManager.Relate(hair, pack); 86 _mManager.Relate(clothes, pack); 87 88 // Create and assign Resources. 89 // MyResource is just custom user class. The API can accept any object as resource. 90 var jake = new MyResource() { Name = "Jake" }; 91 var peter = new MyResource() { Name = "Peter" }; 92 var john = new MyResource() { Name = "John" }; 93 var lucas = new MyResource() { Name = "Lucas" }; 94 var james = new MyResource() { Name = "James" }; 95 var mary = new MyResource() { Name = "Mary" }; 96 // Add some resources 97 _mManager.Assign(wake, jake); 98 _mManager.Assign(wake, peter); 99 _mManager.Assign(wake, john); 100 _mManager.Assign(teeth, jake); 101 _mManager.Assign(teeth, james); 102 _mManager.Assign(pack, james); 103 _mManager.Assign(pack, lucas); 104 _mManager.Assign(shower, mary); 105 _mManager.Assign(shower, lucas); 106 _mManager.Assign(shower, john); 107 108 // Initialize the Chart with our ProjectManager and CreateTaskDelegate 109 _mChart.Init(_mManager); 110 _mChart.CreateTaskDelegate = delegate() { return new MyTask(_mManager); }; 111 112 // Attach event listeners for events we are interested in 113 _mChart.TaskMouseOver += new EventHandler<TaskMouseEventArgs>(_mChart_TaskMouseOver); 114 _mChart.TaskMouseOut += new EventHandler<TaskMouseEventArgs>(_mChart_TaskMouseOut); 115 _mChart.TaskSelected += new EventHandler<TaskMouseEventArgs>(_mChart_TaskSelected); 116 _mChart.PaintOverlay += _mOverlay.ChartOverlayPainter; 117 _mChart.AllowTaskDragDrop = true; 118 119 // set some tooltips to show the resources in each task 120 _mChart.SetToolTip(wake, string.Join(", ", _mManager.ResourcesOf(wake).Select(x => (x as MyResource).Name))); 121 _mChart.SetToolTip(teeth, string.Join(", ", _mManager.ResourcesOf(teeth).Select(x => (x as MyResource).Name))); 122 _mChart.SetToolTip(pack, string.Join(", ", _mManager.ResourcesOf(pack).Select(x => (x as MyResource).Name))); 123 _mChart.SetToolTip(shower, string.Join(", ", _mManager.ResourcesOf(shower).Select(x => (x as MyResource).Name))); 124 125 // Set Time information 126 _mManager.TimeScale = TimeScale.Day; 127 var span = DateTime.Today - _mManager.Start; 128 _mManager.Now = (int)Math.Round(span.TotalDays); // set the "Now" marker at the correct date 129 _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek; // Set the chart to display days of week in header 130 131 // Init the rest of the UI 132 _InitExampleUI(); 133 } 134 135 void _mChart_TaskSelected(object sender, TaskMouseEventArgs e) 136 { 137 _mTaskGrid.SelectedObjects = _mChart.SelectedTasks.Select(x => _mManager.IsPart(x) ? _mManager.SplitTaskOf(x) : x).ToArray(); 138 _mResourceGrid.Items.Clear(); 139 _mResourceGrid.Items.AddRange(_mManager.ResourcesOf(e.Task).Select(x => new ListViewItem(((MyResource)x).Name)).ToArray()); 140 } 141 142 void _mChart_TaskMouseOut(object sender, TaskMouseEventArgs e) 143 { 144 lblStatus.Text = ""; 145 _mChart.Invalidate(); 146 } 147 148 void _mChart_TaskMouseOver(object sender, TaskMouseEventArgs e) 149 { 150 lblStatus.Text = string.Format("{0} to {1}", _mManager.GetDateTime(e.Task.Start).ToLongDateString(), _mManager.GetDateTime(e.Task.End).ToLongDateString()); 151 _mChart.Invalidate(); 152 } 153 154 private void _InitExampleUI() 155 { 156 TaskGridView.DataSource = new BindingSource(_mManager.Tasks, null); 157 mnuFilePrint200.Click += (s, e) => _PrintDocument(2.0f); 158 mnuFilePrint150.Click += (s, e) => _PrintDocument(1.5f); 159 mnuFilePrint100.Click += (s, e) => _PrintDocument(1.0f); 160 mnuFilePrint80.Click += (s, e) => _PrintDocument(0.8f); 161 mnuFilePrint50.Click += (s, e) => _PrintDocument(0.5f); 162 mnuFilePrint25.Click += (s, e) => _PrintDocument(0.25f); 163 mnuFilePrint10.Click += (s, e) => _PrintDocument(0.1f); 164 165 mnuFileImgPrint100.Click += (s, e) => _PrintImage(1.0f); 166 mnuFileImgPrint50.Click += (s, e) => _PrintImage(0.5f); 167 mnuFileImgPrint10.Click += (s, e) => _PrintImage(0.1f); 168 } 169 170 #region Main Menu 171 172 private void mnuFileSave_Click(object sender, EventArgs e) 173 { 174 using (var dialog = new SaveFileDialog()) 175 { 176 dialog.InitialDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath); 177 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) 178 { 179 using (var fs = System.IO.File.OpenWrite(dialog.FileName)) 180 { 181 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 182 bf.Serialize(fs, _mManager); 183 } 184 } 185 } 186 } 187 188 private void mnuFileOpen_Click(object sender, EventArgs e) 189 { 190 using (var dialog = new OpenFileDialog()) 191 { 192 dialog.InitialDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath); 193 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) 194 { 195 using (var fs = System.IO.File.OpenRead(dialog.FileName)) 196 { 197 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 198 _mManager = bf.Deserialize(fs) as ProjectManager; 199 if (_mManager == null) 200 { 201 MessageBox.Show("Unable to load ProjectManager. Data structure might have changed from previous verions", "Gantt Chart", MessageBoxButtons.OK, MessageBoxIcon.Error); 202 } 203 else 204 { 205 _mChart.Init(_mManager); 206 _mChart.Invalidate(); 207 } 208 } 209 } 210 } 211 } 212 213 private void mnuFileExit_Click(object sender, EventArgs e) 214 { 215 this.Close(); 216 } 217 218 private void mnuViewDaysDayOfWeek_Click(object sender, EventArgs e) 219 { 220 _mManager.TimeScale = TimeScale.Day; 221 _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek; 222 _mChart.Invalidate(); 223 } 224 225 private void mnuFileNew_Click(object sender, EventArgs e) 226 { 227 // start a new Project and init the chart with the project 228 _mManager = new ProjectManager(); 229 _mManager.Add(new Task() { Name = "New Task" }); 230 _mChart.Init(_mManager); 231 _mChart.Invalidate(); 232 } 233 234 private void mnuHelpAbout_Click(object sender, EventArgs e) 235 { 236 if (MessageBox.Show("Please visit http://www.jakesee.com/net-c-winforms-gantt-chart-control/ for more help and details", "Braincase Solutions - Gantt Chart", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK) 237 { 238 System.Diagnostics.Process.Start("http://www.jakesee.com/net-c-winforms-gantt-chart-control/"); 239 } 240 } 241 242 private void mnuViewRelationships_Click(object sender, EventArgs e) 243 { 244 _mChart.ShowRelations = mnuViewRelationships.Checked = !mnuViewRelationships.Checked; 245 _mChart.Invalidate(); 246 } 247 248 private void mnuViewSlack_Click(object sender, EventArgs e) 249 { 250 _mChart.ShowSlack = mnuViewSlack.Checked = !mnuViewSlack.Checked; 251 _mChart.Invalidate(); 252 } 253 254 private void mnuViewIntructions_Click(object sender, EventArgs e) 255 { 256 _mOverlay.PrintMode = !(mnuViewIntructions.Checked = !mnuViewIntructions.Checked); 257 _mChart.Invalidate(); 258 } 259 260 #region Timescale Views 261 private void mnuViewDays_Click(object sender, EventArgs e) 262 { 263 _mManager.TimeScale = TimeScale.Day; 264 mnuViewDays.Checked = true; 265 mnuViewWeek.Checked = false; 266 _mChart.Invalidate(); 267 } 268 269 private void mnuViewWeek_Click(object sender, EventArgs e) 270 { 271 _mManager.TimeScale = TimeScale.Week; 272 mnuViewDays.Checked = false; 273 mnuViewWeek.Checked = true; 274 _mChart.Invalidate(); 275 } 276 277 private void mnuViewDayOfWeek_Click(object sender, EventArgs e) 278 { 279 _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek; 280 mnuViewDayOfWeek.Checked = true; 281 mnuViewDayOfMonth.Checked = false; 282 mnuViewWeekOfYear.Checked = false; 283 _mChart.Invalidate(); 284 } 285 286 private void mnuViewDayOfMonth_Click(object sender, EventArgs e) 287 { 288 _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfMonth; 289 mnuViewDayOfWeek.Checked = false; 290 mnuViewDayOfMonth.Checked = true; 291 mnuViewWeekOfYear.Checked = false; 292 _mChart.Invalidate(); 293 } 294 295 private void mnuViewWeekOfYear_Click(object sender, EventArgs e) 296 { 297 _mChart.TimeScaleDisplay = TimeScaleDisplay.WeekOfYear; 298 mnuViewDayOfWeek.Checked = false; 299 mnuViewDayOfMonth.Checked = false; 300 mnuViewWeekOfYear.Checked = true; 301 _mChart.Invalidate(); 302 } 303 #endregion Timescale Views 304 305 #endregion Main Menu 306 307 #region Sidebar 308 309 private void _mDateTimePicker_ValueChanged(object sender, EventArgs e) 310 { 311 _mManager.Start = _mStartDatePicker.Value; 312 var span = DateTime.Today - _mManager.Start; 313 _mManager.Now = (int)Math.Round(span.TotalDays); 314 if (_mManager.TimeScale == TimeScale.Week) _mManager.Now = (_mManager.Now % 7) * 7; 315 _mChart.Invalidate(); 316 } 317 318 private void _mPropertyGrid_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e) 319 { 320 _mChart.Invalidate(); 321 } 322 323 private void _mNowDatePicker_ValueChanged(object sender, EventArgs e) 324 { 325 TimeSpan span = _mNowDatePicker.Value - _mStartDatePicker.Value; 326 _mManager.Now = span.Days + 1; 327 if (_mManager.TimeScale == TimeScale.Week) _mManager.Now = _mManager.Now / 7 + (_mManager.Now % 7 > 0 ? 1 : 0); 328 _mChart.Invalidate(); 329 } 330 331 private void _mScrollDatePicker_ValueChanged(object sender, EventArgs e) 332 { 333 _mChart.ScrollTo(_mScrollDatePicker.Value); 334 _mChart.Invalidate(); 335 } 336 337 private void _mTaskGridView_SelectionChanged(object sender, EventArgs e) 338 { 339 if (TaskGridView.SelectedRows.Count > 0) 340 { 341 var task = TaskGridView.SelectedRows[0].DataBoundItem as Task; 342 _mChart.ScrollTo(task); 343 } 344 } 345 346 #endregion Sidebar 347 348 #region Print 349 350 private void _PrintDocument(float scale) 351 { 352 using (var dialog = new PrintDialog()) 353 { 354 dialog.Document = new System.Drawing.Printing.PrintDocument(); 355 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) 356 { 357 // set the print mode for the custom overlay painter so that we skip printing instructions 358 dialog.Document.BeginPrint += (s, arg) => _mOverlay.PrintMode = true; 359 dialog.Document.EndPrint += (s, arg) => _mOverlay.PrintMode = false; 360 361 // tell chart to print to the document at the specified scale 362 _mChart.Print(dialog.Document, scale); 363 } 364 } 365 } 366 367 private void _PrintImage(float scale) 368 { 369 using (var dialog = new SaveFileDialog()) 370 { 371 dialog.Filter = "Bitmap (*.bmp) | *.bmp"; 372 if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) 373 { 374 // set the print mode for the custom overlay painter so that we skip printing instructions 375 _mOverlay.PrintMode = true; 376 // tell chart to print to the document at the specified scale 377 378 var bitmap = _mChart.Print(scale); 379 _mOverlay.PrintMode = false; // restore printing overlays 380 381 bitmap.Save(dialog.FileName, System.Drawing.Imaging.ImageFormat.Bmp); 382 } 383 } 384 } 385 386 #endregion Print 387 388 389 } 390 391 #region overlay painter 392 /// <summary> 393 /// An example of how to encapsulate a helper painter for painter additional features on Chart 394 /// </summary> 395 public class OverlayPainter 396 { 397 /// <summary> 398 /// Hook such a method to the chart paint event listeners 399 /// </summary> 400 /// <param name="sender"></param> 401 /// <param name="e"></param> 402 public void ChartOverlayPainter(object sender, ChartPaintEventArgs e) 403 { 404 // Don't want to print instructions to file 405 if (this.PrintMode) return; 406 407 var g = e.Graphics; 408 var chart = e.Chart; 409 410 // Demo: Static billboards begin ----------------------------------- 411 // Demonstrate how to draw static billboards 412 // "push matrix" -- save our transformation matrix 413 e.Chart.BeginBillboardMode(e.Graphics); 414 415 // draw mouse command instructions 416 int margin = 300; 417 int left = 20; 418 var color = chart.HeaderFormat.Color; 419 StringBuilder builder = new StringBuilder(); 420 builder.AppendLine("THIS IS DRAWN BY A CUSTOM OVERLAY PAINTER TO SHOW DEFAULT MOUSE COMMANDS."); 421 builder.AppendLine("*******************************************************************************************************"); 422 builder.AppendLine("Left Click - Select task and display properties in PropertyGrid"); 423 builder.AppendLine("Left Mouse Drag - Change task starting point"); 424 builder.AppendLine("Right Mouse Drag - Change task duration"); 425 builder.AppendLine("Middle Mouse Drag - Change task complete percentage"); 426 builder.AppendLine("Left Doubleclick - Toggle collaspe on task group"); 427 builder.AppendLine("Right Doubleclick - Split task into task parts"); 428 builder.AppendLine("Left Mouse Dragdrop onto another task - Group drag task under drop task"); 429 builder.AppendLine("Right Mouse Dragdrop onto another task part - Join task parts"); 430 builder.AppendLine("SHIFT + Left Mouse Dragdrop onto another task - Make drop task precedent of drag task"); 431 builder.AppendLine("ALT + Left Dragdrop onto another task - Ungroup drag task from drop task / Remove drop task from drag task precedent list"); 432 builder.AppendLine("SHIFT + Left Mouse Dragdrop - Order tasks"); 433 builder.AppendLine("SHIFT + Middle Click - Create new task"); 434 builder.AppendLine("ALT + Middle Click - Delete task"); 435 builder.AppendLine("Left Doubleclick - Toggle collaspe on task group"); 436 var size = g.MeasureString(builder.ToString(), e.Chart.Font); 437 var background = new Rectangle(left, chart.Height - margin, (int)size.Width, (int)size.Height); 438 background.Inflate(10, 10); 439 g.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(background, Color.LightYellow, Color.Transparent, System.Drawing.Drawing2D.LinearGradientMode.Vertical), background); 440 g.DrawRectangle(Pens.Brown, background); 441 g.DrawString(builder.ToString(), chart.Font, color, new PointF(left, chart.Height - margin)); 442 443 444 // "pop matrix" -- restore the previous matrix 445 e.Chart.EndBillboardMode(e.Graphics); 446 // Demo: Static billboards end ----------------------------------- 447 } 448 449 public bool PrintMode { get; set; } 450 } 451 #endregion overlay painter 452 453 #region custom task and resource 454 /// <summary> 455 /// A custom resource of your own type (optional) 456 /// </summary> 457 [Serializable] 458 public class MyResource 459 { 460 public string Name { get; set; } 461 } 462 /// <summary> 463 /// A custom task of your own type deriving from the Task interface (optional) 464 /// </summary> 465 [Serializable] 466 public class MyTask : Task 467 { 468 public MyTask(ProjectManager manager) 469 : base() 470 { 471 Manager = manager; 472 } 473 474 private ProjectManager Manager { get; set; } 475 476 public new int Start { get { return base.Start; } set { Manager.SetStart(this, value); } } 477 public new int End { get { return base.End; } set { Manager.SetEnd(this, value); } } 478 public new int Duration { get { return base.Duration; } set { Manager.SetDuration(this, value); } } 479 public new float Complete { get { return base.Complete; } set { Manager.SetComplete(this, value); } } 480 } 481 #endregion custom task and resource 482 }
演示效果图为:
转载于:https://www.cnblogs.com/isaboy/p/ganttcontrol.html
一款开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control相关推荐
- 甘特图控件VARCHART XGantt的功能亮点
甘特图(Xgantt)从1998年的第一个商用版本开始就致力于计划编制和项目管理方面控件的研究和开发,经过20多年的积累和沉淀,目前可为软件开发商和最终用户提供最顶级的计划编制和项目管理的控件产品,帮 ...
- Linux带箭头的截图软件,推荐一款Linux下功能强大全面的屏幕截图软件
原标题:推荐一款Linux下功能强大全面的屏幕截图软件 今天推荐大家使用Flameshot(火焰),因为它是我个人最喜欢屏幕截图软件.如果你不知道,Flameshot是一个Linux可用的开源截屏工具 ...
- 最后防线:三款开源HIDS功能对比评估
本文是对Wazuh, Osquery, AgentSmith这三款开源HIDS进行功能性的评估,目的是取长补短,做一个完善的HIDS系统. 简介 HIDS的功能主要是依靠agent的数据收集功能, 所 ...
- 推荐三款强大且漂亮的统计图控件
志在必得(Xuon) 一.免费且强大的Flash统计图--FusionChartsFree 官方网址: http://www.fusioncharts.com/free/ 效果图: 使用感想: 对.N ...
- 9 款样式华丽的 jQuery 日期选择和日历控件
现在的网页应用越来越丰富,我们在网页中填写日期和时间已经再也不用手动输入了,而是使用各种各样的日期时间选择控件,大部分样式华丽的日期选择和日历控件都是基于jQuery和HTML5的,比如今天要分享的这 ...
- 被误认为是外国人开发的4款软件,功能强大到离谱,且用且珍惜
国外的月亮不一定比国内圆,随着国内互联网飞速发展,国内研发出许多实用又良心的软件,由于偏见,功能强大的它们却被误认为是外国佬研发的. 1.Foxit PDF用系统自带的Adobe实在难用,Foxit这 ...
- 一款简单免费功能强大的截图软件Snipaste
功能强大的截图工具Snipaste, 免费而且还免安装,没有广告,非常安全.直接下载安装包便可以使用,这让截图更加方便,省时省力,大大的提高了我们的完成效率. 在使用中我觉得它最好的地方可以贴图,极大 ...
- Excel催化剂开源第13波-VSTO开发之DataGridView控件几个小坑
Excel催化剂内部大量使用了DataGridView,这其中有一些小坑,花了力气才解决的,在此给广大开发者作简单分享. 为何要使用DataGridView而不是其他控件如ListBox.ListVi ...
- 如何快速写一款小而美的“上滑无限加载的控件”?| 博文精选
作者 | ShuSheng007 责编 | 郭芮 出品 | CSDN博客 在日常从事Android开发工作时,经常会遇到下拉刷新列表页面,上拉自动加载列表的需求, GitHub上已经有很多关于这方面的 ...
最新文章
- 如何在Git中保存用户名和密码?
- Codeforces Round #476 (Div. 2) B. Battleship
- 如何采用锂离子电池提高数据中心电源效率
- HighNewTech:70后、80后、90后、95后职场人大数据调查(有趣的五个结论)——源于猎聘网
- VC/MFC Combo Box控件的用法
- 音视频出海,如何乘风破浪?
- Vue_异步加载_vue-resource(不再维护)
- 使用现代化 C# 语法简化代码
- leetcode —— 1319. 连通网络的操作次数
- 链路层 - SLIP,PPP,
- 使用jsp实现文件上传的功能
- 部署LNMP架构及其应用
- 隐藏java_Java方法隐藏
- net core Autofac
- Silverlight Telerik控件学习:主题Theme切换
- CRC源码生成工具,可生成Verilog和VHDL
- tar、rpm和yum总结
- python做后端速度慢吗_【后端开发】python如何提高运行速度
- 【用jersey构建REST服务】系列文章
- echarts地图设置label引导线
热门文章
- hp服务器pe系统安装win7系统安装系统安装,惠普Folio 1040 G1 u盘pe如何重装win7系统...
- python pip install 总是出错的解决方法_pip安装总是失败怎么办? 3个方法帮你解决...
- scala中命名参数函数_Scala中的命名参数和默认参数值
- Sobel边缘检测算法及OpenCV函数实现
- Python写数据结构:双向循环链表
- vue canvas动效组件插件库制作
- SpringBoot(Properties)
- php模拟input 的file上传文件
- Linux关机重启指令
- Nginx如何配置静态文件过期时间