我已经用谷歌搜索了这个问题的答案,但我似乎找不到任何好的实例。我创建了一个名为StarControl的自定义星级用户控件。控件基本上是五个相互水平相邻的图片框,我有以下代码:
public partial class StarControl : UserControl
{
private enum StarTypes
{
Hollow,
Filled
}
private readonly StarTypes[] _stars;
private int _rating;
public StarControl()
{
InitializeComponent();
Locked = false;
_stars = new StarTypes[5];
_stars[0] = StarTypes.Hollow;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 0;
SetStars();
}
public bool Locked
{
get;
set;
}
public int Rating
{
get { return _rating; }
set { _rating = value; SetRating(); }
}
private void SetRating()
{
if (_rating == 0)
{
_stars[0] = StarTypes.Hollow;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
}
if (_rating == 1)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
}
if (_rating == 2)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
}
if (_rating == 3)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Filled;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
}
if (_rating == 4)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Filled;
_stars[3] = StarTypes.Filled;
_stars[4] = StarTypes.Hollow;
}
if (_rating == 5)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Filled;
_stars[3] = StarTypes.Filled;
_stars[4] = StarTypes.Filled;
}
SetStars();
}
private void SetStars()
{
pbStar1.Image = _stars[0] == StarTypes.Hollow
? Properties.Resources.star_hollow
: Properties.Resources.star_filled;
pbStar2.Image = _stars[1] == StarTypes.Hollow
? Properties.Resources.star_hollow
: Properties.Resources.star_filled;
pbStar3.Image = _stars[2] == StarTypes.Hollow
? Properties.Resources.star_hollow
: Properties.Resources.star_filled;
pbStar4.Image = _stars[3] == StarTypes.Hollow
? Properties.Resources.star_hollow
: Properties.Resources.star_filled;
pbStar5.Image = _stars[4] == StarTypes.Hollow
? Properties.Resources.star_hollow
: Properties.Resources.star_filled;
}
private void PbStar1MouseEnter(object sender, EventArgs e)
{
if (!Locked)
{
pbStar1.Image = Properties.Resources.star_filled;
pbStar2.Image = Properties.Resources.star_hollow;
pbStar3.Image = Properties.Resources.star_hollow;
pbStar4.Image = Properties.Resources.star_hollow;
pbStar5.Image = Properties.Resources.star_hollow;
}
}
private void PbStar1MouseLeave(object sender, EventArgs e)
{
if (!Locked)
{
SetStars();
}
}
private void PbStar2MouseEnter(object sender, EventArgs e)
{
if (!Locked)
{
pbStar1.Image = Properties.Resources.star_filled;
pbStar2.Image = Properties.Resources.star_filled;
pbStar3.Image = Properties.Resources.star_hollow;
pbStar4.Image = Properties.Resources.star_hollow;
pbStar5.Image = Properties.Resources.star_hollow;
}
}
private void PbStar2MouseLeave(object sender, EventArgs e)
{
if (!Locked)
{
SetStars();
}
}
private void PbStar3MouseEnter(object sender, EventArgs e)
{
if (!Locked)
{
pbStar1.Image = Properties.Resources.star_filled;
pbStar2.Image = Properties.Resources.star_filled;
pbStar3.Image = Properties.Resources.star_filled;
pbStar4.Image = Properties.Resources.star_hollow;
pbStar5.Image = Properties.Resources.star_hollow;
}
}
private void PbStar3MouseLeave(object sender, EventArgs e)
{
if (!Locked)
{
SetStars();
}
}
private void PbStar4MouseEnter(object sender, EventArgs e)
{
if (!Locked)
{
pbStar1.Image = Properties.Resources.star_filled;
pbStar2.Image = Properties.Resources.star_filled;
pbStar3.Image = Properties.Resources.star_filled;
pbStar4.Image = Properties.Resources.star_filled;
pbStar5.Image = Properties.Resources.star_hollow;
}
}
private void PbStar4MouseLeave(object sender, EventArgs e)
{
if (!Locked)
{
SetStars();
}
}
private void PbStar5MouseEnter(object sender, EventArgs e)
{
if (!Locked)
{
pbStar1.Image = Properties.Resources.star_filled;
pbStar2.Image = Properties.Resources.star_filled;
pbStar3.Image = Properties.Resources.star_filled;
pbStar4.Image = Properties.Resources.star_filled;
pbStar5.Image = Properties.Resources.star_filled;
}
}
private void PbStar5MouseLeave(object sender, EventArgs e)
{
if (!Locked)
{
SetStars();
}
}
private void PbStar1MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && !Locked)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 1;
}
if (e.Button == MouseButtons.Right && !Locked)
{
_stars[0] = StarTypes.Hollow;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 0;
}
SetStars();
}
private void PbStar2MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && !Locked)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 2;
}
if (e.Button == MouseButtons.Right && !Locked)
{
_stars[0] = StarTypes.Hollow;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 0;
}
SetStars();
}
private void PbStar3MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && !Locked)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Filled;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 3;
}
if (e.Button == MouseButtons.Right && !Locked)
{
_stars[0] = StarTypes.Hollow;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 0;
}
SetStars();
}
private void PbStar4MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && !Locked)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Filled;
_stars[3] = StarTypes.Filled;
_stars[4] = StarTypes.Hollow;
Rating = 4;
}
if (e.Button == MouseButtons.Right && !Locked)
{
_stars[0] = StarTypes.Hollow;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 0;
}
SetStars();
}
private void PbStar5MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && !Locked)
{
_stars[0] = StarTypes.Filled;
_stars[1] = StarTypes.Filled;
_stars[2] = StarTypes.Filled;
_stars[3] = StarTypes.Filled;
_stars[4] = StarTypes.Filled;
Rating = 5;
}
if (e.Button == MouseButtons.Right && !Locked)
{
_stars[0] = StarTypes.Hollow;
_stars[1] = StarTypes.Hollow;
_stars[2] = StarTypes.Hollow;
_stars[3] = StarTypes.Hollow;
_stars[4] = StarTypes.Hollow;
Rating = 0;
}
SetStars();
}
}
控件工作得很好。在我的表单上,我有一个DataGridView控件,我正在尝试使用集合中的行动态填充DataGridView。该集合只是这个类的集合:
[Serializable]
public class Rating
{
public string VendorName { get; set; }
public int VendorRating { get; set; }
}
public List<Rating> _myRatings;
VendorName
只是一个字符串,VendorRating
是一个int,表示0-5之间的数字。通过在我的Rating
上设置StarControl
属性,它会显示星数。我要做的是弄清楚如何让StarControl
用户控件显示在DataGridView
上。有人可以请我提供一个如何做到这一点的例子吗?
我在这个主题上看过this MSDN article,但我不认为这适用于我,因为它们只是继承自DataGridViewTextBoxCell
,我的控制权比日期/时间更复杂文本框。
答案 0 :(得分:8)
出于这样的目的,您根本不需要这样的控制。与DataGridView
的附件有点棘手。我不想在这种方法后给你一个解决方案,但我只想分享一些关于如何实现它的信息。首先,您必须计算总显示的单元格,您需要 List<YourControl>
来存储所有需要的控件。这些控件必须将DataGridView
作为Parent
。这些控件的数量必须等于显示的单元格数。然后在CellPainting
事件处理程序中,您必须更新列表中所有控件的位置。我们在 CellPainting 事件处理程序中添加位置更新代码,因为无论何时更新单元格值和边界,都会触发 CellPainting 并相应地更新控件“Location
。这有点棘手但确实有效。您可以通过某些引用属性将每个控件与每个单元格相关联,例如Tag
属性。
现在,我想与您分享这种更好的方法。您只需为自定义DataGridViewCell
创建用作CellTemplate
的自定义DataGridViewColumn
。我们必须使用GDI+
进行一些绘画并编写相当多的代码。请注意,我为自己编写了这个演示,但是在阅读完问题之后就开始了。用这样一个完整的代码回答问题并不是真的搞笑,它耗费了很多时间,但正如我所说,我打算自己使用这个演示,现在我只想和你分享。事实上,为了给你一些想法,代码可以简化得更多:
public class DataGridViewRatingColumn : DataGridViewColumn {
public DataGridViewRatingColumn() : base(new DataGridViewRatingCell()) {
base.ReadOnly = true;
RatedStarColor = Color.Green;
GrayStarColor = Color.LightGray;
StarScale = 1;
}
bool readOnly;
public new bool ReadOnly
{
get {
return readOnly;
}
set {
readOnly = value;
}
}
Color ratedStarColor;
Color grayStarColor;
float starScale;
public Color RatedStarColor {
get { return ratedStarColor; }
set {
if (ratedStarColor != value) {
ratedStarColor = value;
if (DataGridView != null) DataGridView.InvalidateColumn(Index);
}
}
}
public Color GrayStarColor
{
get { return grayStarColor; }
set {
if (grayStarColor != value){
grayStarColor = value;
if(DataGridView != null) DataGridView.InvalidateColumn(Index);
}
}
}
public float StarScale {
get { return starScale; }
set {
if (starScale != value) {
starScale = value;
DataGridViewRatingCell.UpdateBrushes(value);
if (DataGridView != null) DataGridView.InvalidateColumn(Index);
}
}
}
}
public class DataGridViewRatingCell : DataGridViewTextBoxCell {
static DataGridViewRatingCell() {
//Init star
List<PointF> points = new List<PointF>();
bool largeArc = true;
R = 10;
r = 4;
center = new Point(R, R);
for (float alpha = 90; alpha <= 414; alpha += 36)
{
int d = largeArc ? R : r;
double radAlpha = alpha * Math.PI / 180;
float x = (float)(d * Math.Cos(radAlpha));
float y = (float)(d * Math.Sin(radAlpha));
points.Add(new PointF(center.X + x, center.Y + y));
largeArc = !largeArc;
}
star.AddPolygon(points.ToArray());
star.Transform(new Matrix(1, 0, 0, -1, 0, center.Y * 2));
//Init stars
UpdateBrushes(1);
}
public DataGridViewRatingCell() {
ValueType = typeof(int);
ratedStarColor = Color.Green;
grayStarColor = Color.LightGray;
starScale = 1;
UseColumnStarColor = true;
UseColumnStarScale = true;
}
public override object DefaultNewRowValue {
get {
return 0;
}
}
internal static void UpdateBrushes(float scale) {
int space = 2*R;
for (int i = 0; i < 5; i++) {
if (stars[i] != null) stars[i].Dispose();
stars[i] = (GraphicsPath)star.Clone();
stars[i].Transform(new Matrix(scale, 0, 0, scale, space * i * scale, 0));
brushes[i] = CreateBrush(new RectangleF(center.X - R + space * i * scale, center.Y - R, R * 2 * scale, R * 2 * scale));
}
}
private static LinearGradientBrush CreateBrush(RectangleF bounds)
{
var brush = new LinearGradientBrush(bounds,Color.White, Color.Yellow, LinearGradientMode.ForwardDiagonal);
ColorBlend cb = new ColorBlend();
Color c = Color.Green;
Color lightColor = Color.White;
cb.Colors = new Color[] { c, c, lightColor, c, c };
cb.Positions = new float[] { 0, 0.4f, 0.5f, 0.6f, 1 };
brush.InterpolationColors = cb;
return brush;
}
private void AdjustBrushColors(LinearGradientBrush brush, Color baseColor, Color lightColor)
{
//Note how we adjust the colors, using brush.InterpolationColors directly won't work.
ColorBlend cb = brush.InterpolationColors;
cb.Colors = new Color[] { baseColor, baseColor, lightColor, baseColor, baseColor };
brush.InterpolationColors = cb;
}
static GraphicsPath star = new GraphicsPath();
static GraphicsPath[] stars = new GraphicsPath[5];
static LinearGradientBrush[] brushes = new LinearGradientBrush[5];
static Point center;
static int R, r;
int currentValue = -1;
bool mouseOver;
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds,
int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue,
string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue,
errorText, cellStyle, advancedBorderStyle, paintParts & ~DataGridViewPaintParts.SelectionBackground & ~DataGridViewPaintParts.ContentForeground);
if (rowIndex == RowIndex && (paintParts & DataGridViewPaintParts.ContentForeground) != 0) {
graphics.SmoothingMode = SmoothingMode.AntiAlias;
if(Value != null) Value = Math.Min(Math.Max(0, (int)Value), 5);
if (!mouseOver) currentValue = (int)(Value ?? 0);
PaintStars(graphics, cellBounds, 0, currentValue, true);
PaintStars(graphics, cellBounds, currentValue, 5 - currentValue, false);
graphics.SmoothingMode = SmoothingMode.Default;
}
}
protected override void OnMouseMove(DataGridViewCellMouseEventArgs e) {
base.OnMouseMove(e);
if (!mouseOver) mouseOver = true;
if (IsReadOnly()) return;
var lastStar = stars.Select((x, i) => new { x, i })
.LastOrDefault(x => x.x.IsVisible(e.Location));
if (lastStar != null) {
currentValue = lastStar.i + 1;
DataGridView.Cursor = Cursors.Hand;
}
else if(RowIndex > -1) {
currentValue = (int)(Value ?? 0);
DataGridView.Cursor = Cursors.Default;
}
DataGridView.InvalidateCell(this);
}
protected override void OnClick(DataGridViewCellEventArgs e) {
base.OnClick(e);
if (IsReadOnly()) return;
Value = currentValue == 1 && (int?) Value == 1 ? 0 : currentValue;
}
protected override void OnMouseLeave(int rowIndex) {
base.OnMouseLeave(rowIndex);
mouseOver = false;
if (IsReadOnly()) return;
if (rowIndex == RowIndex) {
currentValue = (int)(Value ?? 0);
DataGridView.InvalidateCell(this);
}
}
private bool IsReadOnly() {
var col = OwningColumn as DataGridViewRatingColumn;
return col != null ? col.ReadOnly : false;
}
private void PaintStars(Graphics g, Rectangle bounds, int startIndex, int count, bool rated) {
GraphicsState gs = g.Save();
g.TranslateTransform(bounds.Left, bounds.Top);
var col = OwningColumn as DataGridViewRatingColumn;
Color ratedColor = col == null ? Color.Yellow :
UseColumnStarColor ? col.RatedStarColor : RatedStarColor;
Color grayColor = col == null ? Color.LightGray :
UseColumnStarColor ? col.GrayStarColor : GrayStarColor;
float starScale = col == null ? 1 :
UseColumnStarScale ? col.StarScale : StarScale;
UpdateBrushes(starScale);
for(int i = startIndex; i < startIndex + count; i++) {
AdjustBrushColors(brushes[i], rated ? ratedColor : grayColor, rated ? Color.White : grayColor);
g.FillPath(brushes[i], stars[i]);
//g.DrawPath(Pens.Green, stars[i]);
}
g.Restore(gs);
}
Color ratedStarColor;
Color grayStarColor;
float starScale;
public Color RatedStarColor {
get { return ratedStarColor; }
set {
if (ratedStarColor != value) {
ratedStarColor = value;
var col = OwningColumn as DataGridViewRatingColumn;
if (col != null && col.RatedStarColor != value) {
UseColumnStarColor = false;
DataGridView.InvalidateCell(this);
}
}
}
}
public Color GrayStarColor {
get { return grayStarColor; }
set {
if (grayStarColor != value) {
grayStarColor = value;
var col = OwningColumn as DataGridViewRatingColumn;
if (col != null && col.GrayStarColor != value) {
UseColumnStarColor = false;
DataGridView.InvalidateCell(this);
}
}
}
}
//Change the star size via scaling factor (default by 1)
public float StarScale {
get { return starScale; }
set {
if (starScale != value) {
starScale = value;
var col = OwningColumn as DataGridViewRatingColumn;
if (col != null && col.StarScale != value) {
UseColumnStarScale = false;
DataGridView.InvalidateCell(this);
}
}
}
}
public bool UseColumnStarColor { get; set; }
public bool UseColumnStarScale { get; set; }
}
注意:2个类DataGridViewRatingColumn
和DataGridViewRatingCell
应该放在同一个文件中,因为我在{{1}中声明了一个静态内部方法UpdateBrushes
并且在类DataGridViewRatingCell
中使用它,如果要将它们放在单独的文件中,可以更改修饰符。查看提供的属性并使用它们来自定义星星的外观和感觉。它们以不言自明的方式命名。以下是一些显示用法的代码:
DataGridViewRatingColumn
答案 1 :(得分:2)
在datagridview中显示星级的最佳方式 使用unicode char
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == dataGridView1.Columns["Rating"].Index
&& e.Value != null)
{
switch (e.Value.ToString())
{
case "1":
e.CellStyle.SelectionForeColor = Color.Red;
e.CellStyle.ForeColor = Color.Red;
//e.CellStyle.Font
e.Value = (char)9733;
break;
case "2":
e.CellStyle.SelectionForeColor = Color.Brown;
e.CellStyle.ForeColor = Color.Yellow;
e.Value = (char)9733;
break;
case "3":
e.CellStyle.SelectionForeColor = Color.Green;
e.CellStyle.ForeColor = Color.Green;
e.Value = (char)9733;
break;
case "4":
e.CellStyle.SelectionForeColor = Color.Blue;
e.CellStyle.ForeColor = Color.Blue;
e.Value = (char)9733;
break;
case "5":
e.CellStyle.SelectionForeColor = Color.Gold;
e.CellStyle.ForeColor = Color.Gold;
e.Value = (char)9733;
break;
}
}
}