甘特图在项目管理中非常重要,甘特图的思想比较简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间。它直观地表明任务计划在什么时候进行,及实际进展与计划要求的对比。管理者由此可便利地弄清一项任务(项目)还剩下哪些工作要做,并可评估工作进度。甘特图可以显示几个部门、机器或设备的运行和闲置情况。这表示了该系统的有关工作负荷状况,这样可使管理人员了解何种调整是恰当的。

  由于项目需要,在网上找了很久,经过大量的对比和评估,发现一款真正开源且功能强大的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相关推荐

  1. 甘特图控件VARCHART XGantt的功能亮点

    甘特图(Xgantt)从1998年的第一个商用版本开始就致力于计划编制和项目管理方面控件的研究和开发,经过20多年的积累和沉淀,目前可为软件开发商和最终用户提供最顶级的计划编制和项目管理的控件产品,帮 ...

  2. Linux带箭头的截图软件,推荐一款Linux下功能强大全面的屏幕截图软件

    原标题:推荐一款Linux下功能强大全面的屏幕截图软件 今天推荐大家使用Flameshot(火焰),因为它是我个人最喜欢屏幕截图软件.如果你不知道,Flameshot是一个Linux可用的开源截屏工具 ...

  3. 最后防线:三款开源HIDS功能对比评估

    本文是对Wazuh, Osquery, AgentSmith这三款开源HIDS进行功能性的评估,目的是取长补短,做一个完善的HIDS系统. 简介 HIDS的功能主要是依靠agent的数据收集功能, 所 ...

  4. 推荐三款强大且漂亮的统计图控件

    志在必得(Xuon) 一.免费且强大的Flash统计图--FusionChartsFree 官方网址: http://www.fusioncharts.com/free/ 效果图: 使用感想: 对.N ...

  5. 9 款样式华丽的 jQuery 日期选择和日历控件

    现在的网页应用越来越丰富,我们在网页中填写日期和时间已经再也不用手动输入了,而是使用各种各样的日期时间选择控件,大部分样式华丽的日期选择和日历控件都是基于jQuery和HTML5的,比如今天要分享的这 ...

  6. 被误认为是外国人开发的4款软件,功能强大到离谱,且用且珍惜

    国外的月亮不一定比国内圆,随着国内互联网飞速发展,国内研发出许多实用又良心的软件,由于偏见,功能强大的它们却被误认为是外国佬研发的. 1.Foxit PDF用系统自带的Adobe实在难用,Foxit这 ...

  7. 一款简单免费功能强大的截图软件Snipaste

    功能强大的截图工具Snipaste, 免费而且还免安装,没有广告,非常安全.直接下载安装包便可以使用,这让截图更加方便,省时省力,大大的提高了我们的完成效率. 在使用中我觉得它最好的地方可以贴图,极大 ...

  8. Excel催化剂开源第13波-VSTO开发之DataGridView控件几个小坑

    Excel催化剂内部大量使用了DataGridView,这其中有一些小坑,花了力气才解决的,在此给广大开发者作简单分享. 为何要使用DataGridView而不是其他控件如ListBox.ListVi ...

  9. 如何快速写一款小而美的“上滑无限加载的控件”?| 博文精选

    作者 | ShuSheng007 责编 | 郭芮 出品 | CSDN博客 在日常从事Android开发工作时,经常会遇到下拉刷新列表页面,上拉自动加载列表的需求, GitHub上已经有很多关于这方面的 ...

最新文章

  1. 如何在Git中保存用户名和密码?
  2. Codeforces Round #476 (Div. 2) B. Battleship
  3. 如何采用锂离子电池提高数据中心电源效率
  4. HighNewTech:70后、80后、90后、95后职场人大数据调查(有趣的五个结论)——源于猎聘网
  5. VC/MFC Combo Box控件的用法
  6. 音视频出海,如何乘风破浪?
  7. Vue_异步加载_vue-resource(不再维护)
  8. 使用现代化 C# 语法简化代码
  9. leetcode —— 1319. 连通网络的操作次数
  10. 链路层 - SLIP,PPP,
  11. 使用jsp实现文件上传的功能
  12. 部署LNMP架构及其应用
  13. 隐藏java_Java方法隐藏
  14. net core Autofac
  15. Silverlight Telerik控件学习:主题Theme切换
  16. CRC源码生成工具,可生成Verilog和VHDL
  17. tar、rpm和yum总结
  18. python做后端速度慢吗_【后端开发】python如何提高运行速度
  19. 【用jersey构建REST服务】系列文章
  20. echarts地图设置label引导线

热门文章

  1. hp服务器pe系统安装win7系统安装系统安装,惠普Folio 1040 G1 u盘pe如何重装win7系统...
  2. python pip install 总是出错的解决方法_pip安装总是失败怎么办? 3个方法帮你解决...
  3. scala中命名参数函数_Scala中的命名参数和默认参数值
  4. Sobel边缘检测算法及OpenCV函数实现
  5. Python写数据结构:双向循环链表
  6. vue canvas动效组件插件库制作
  7. SpringBoot(Properties)
  8. php模拟input 的file上传文件
  9. Linux关机重启指令
  10. Nginx如何配置静态文件过期时间