在c#中,是否有一种方法可以调用progressbar的绘制逻辑来使它绘制成DataGridViewImageCell
本文关键字:绘制 progressbar 调用 DataGridViewImageCell 是否 方法 一种 | 更新日期: 2023-09-27 17:52:58
我想让一个DataGridViewProgressBar使用本地进度条呈现。我目前有自定义的绘画逻辑来完成这一点,但它看起来不是很好。
好吧,我至少找到了一种方法。我有一个ProgressBar成员变量,我在Cell的Paint逻辑中将其绘制为位图,然后让Cell绘制位图。真正棘手的部分是使细胞动画化。可能有更好的方法,但这里是完整的,可用的代码:
//
// $Id: DataGridViewProgressBar.cs 2051 2010-06-15 18:39:13Z chambm $
//
//
// Original author: Jay Holman <jay.holman .@. vanderbilt.edu>
//
// Copyright 2011 Vanderbilt University - Nashville, TN 37232
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
namespace CustomProgressCell
{
public sealed class DataGridViewProgressColumn : DataGridViewColumn
{
public DataGridViewProgressColumn()
{
CellTemplate = new DataGridViewProgressCell();
}
}
}
namespace CustomProgressCell
{
sealed class DataGridViewProgressCell : DataGridViewTextBoxCell
{
#region Public data accessors
/// <summary>
/// Gets or sets the progress bar's Maximum property.
/// </summary>
public int Maximum
{
get { return _progressBar.Maximum; }
set { _progressBar.Maximum = value; startAnimation(); }
}
/// <summary>
/// Gets or sets the progress bar's Minimum property.
/// </summary>
public int Minimum
{
get { return _progressBar.Minimum; }
set { _progressBar.Minimum = value; startAnimation(); }
}
/// <summary>
/// Gets or sets the text to display on top of the progress bar.
/// </summary>
public string Text
{
get { return _text; }
set { _text = value; refresh(); }
}
/// <summary>
/// Gets or sets the progress bar's drawing style.
/// </summary>
public ProgressBarStyle ProgressBarStyle
{
get { return _progressBar.Style; }
set { _progressBar.Style = value; startAnimation(); }
}
#endregion
/// <summary>
/// Use these keywords in the Text property to their respective values in the text.
/// </summary>
public abstract class MessageSpecialValue
{
public const string Minimum = "<<Minimum>>";
public const string Maximum = "<<Maximum>>";
public const string CurrentValue = "<<CurrentValue>>";
}
#region Private member variables
ProgressBar _progressBar;
Timer _animationStepTimer;
Timer _animationStopTimer;
string _text;
#endregion
public DataGridViewProgressCell()
{
_progressBar = new ProgressBar()
{
Minimum = 0,
Maximum = 100,
Style = ProgressBarStyle.Continuous
};
_text = String.Format("{0} of {1}", MessageSpecialValue.CurrentValue, MessageSpecialValue.Maximum);
ValueType = typeof(int);
// repaint every 25 milliseconds while progress is active
_animationStepTimer = new Timer { Interval = 25, Enabled = true };
// stop repainting 1 second after progress becomes inactive
_animationStopTimer = new Timer { Interval = 1000, Enabled = false };
_animationStepTimer.Tick += (x, y) => { stopAnimation(); refresh(); };
_animationStopTimer.Tick += (x, y) => { _animationStepTimer.Stop(); _animationStopTimer.Stop(); };
}
protected override object GetValue (int rowIndex)
{
return _progressBar.Value;
}
protected override bool SetValue (int rowIndex, object value)
{
if (value is int)
{
_progressBar.Value = (int) value;
refresh();
return true;
}
return false;
}
protected override void Paint (Graphics g, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
ReadOnly = true;
// Draw the cell border
base.Paint(g, clipBounds, cellBounds,
rowIndex, cellState, value, formattedValue, errorText,
cellStyle, advancedBorderStyle, DataGridViewPaintParts.Border);
try
{
// Draw the ProgressBar to an in-memory bitmap
Bitmap bmp = new Bitmap(cellBounds.Width, cellBounds.Height);
Rectangle bmpBounds = new Rectangle(0, 0, cellBounds.Width, cellBounds.Height);
_progressBar.Size = cellBounds.Size;
_progressBar.DrawToBitmap(bmp, bmpBounds);
// Draw the bitmap on the cell
g.DrawImage(bmp, cellBounds);
// Replace special value placeholders
var editedMessage = _text.Replace(MessageSpecialValue.CurrentValue, Value.ToString())
.Replace(MessageSpecialValue.Maximum, Maximum.ToString())
.Replace(MessageSpecialValue.Minimum, Minimum.ToString());
// Write text over bar
base.Paint(g, clipBounds, cellBounds,
rowIndex, cellState, value, editedMessage, errorText,
cellStyle, advancedBorderStyle, DataGridViewPaintParts.ContentForeground);
}
catch (ArgumentOutOfRangeException)
{
// Row probably couldn't be accessed
}
}
private void refresh ()
{
if (DataGridView != null) DataGridView.InvalidateCell(this);
}
private void startAnimation ()
{
if (_progressBar.Style == ProgressBarStyle.Marquee ||
(_progressBar.Value > _progressBar.Minimum && _progressBar.Value < _progressBar.Maximum))
_animationStepTimer.Start();
}
private void stopAnimation ()
{
if (_progressBar.Style != ProgressBarStyle.Marquee &&
(_progressBar.Value == _progressBar.Minimum || _progressBar.Value == _progressBar.Maximum))
_animationStopTimer.Start();
}
}
}
您可以在DataGridView
单元格中托管任何控件。在MSDN上有一个完整的示例:如何:Windows窗体中的主机控件datagridviewcells
所以你可以只使用内置的ProgressBar
控件,它会看起来尽可能的原生。
要回答您关于自定义DataGridViewImageCell
的绘画逻辑以使其像进度条一样绘制的其他问题,它取决于哪个本机进度条渲染您正在谈论。在Windows Aero之前使用的那个非常简单——它只是一个用系统高亮颜色填充的实心矩形。为该控件重新实现绘画逻辑很简单。这就是杰伊所链接的文章试图做的事情。红色的文字在绿色的背景上看起来很难看。如果你要用正确的方法,填充颜色应该是系统的高亮颜色,百分比应该是系统的WindowText颜色。
但是aero主题的进度条看起来完全不同。首先,它们是绿色的,渐变填充的,并且有跳动的效果。这在WinForms中并不容易复制。不久前,我在一个项目上浪费了很多时间,但我放弃了,因为它不太一样。你可以从LinearGradientBrush
开始,但它永远不会看起来完全一样。你仍然不会有搏动和悸动的效果。除了严格的视觉外观,Aero进度条有漂亮的子步骤插值和其他动画效果,将证明更难重新创建。我的诚实的意见是,这是不值得的努力,特别是当使用实际的进度条控件是如此容易。
如果你死心了,这里有一个示例控件让你开始:c#中的Vista风格进度条。
确保当用户禁用Aero主题时,或者他们运行的是旧版本的Windows(如XP),您的逻辑会回落到经典风格的渲染。