winform中datagridview控件怎么根据条件在某一行嵌入自定义控件?

lianying168000 2020-02-13 10:48:46
在做一个测试工具,界面上呈现一批测试用例,用户可以勾选想运行的测试用例,点击启动按钮之后,当前正在运行的测试用例在该Row的右边显示一个转圈的控件(这个我是用picturebox包了一个gif动图的做的),当运行成功之后显示一个绿色的打勾图片,如果失败则显示一个红叉图片。
这个datagridview控件还不是原生的,用的网上的一个HZH_Controls控件库,话说看别人的东西有点头疼,改起来更是。。。

想了半天,没啥思路,求大佬给个思路。。。
...全文
268 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
蒋晟 2020-03-03
  • 打赏
  • 举报
回复
这个再优化一点可以只放一个picturebox,然后根据Mode去设置图片,或者干脆自绘单元格。 你这样一行放三个picturebox,行数一多起来占用的GDI资源会很吓人。
lianying168000 2020-02-16
  • 打赏
  • 举报
回复
辛苦版主大大了,今天上午找到了一个参考例子,他这个例子是根据数据源属性的改变然后在一个单元格绘制进度条,然后我稍微修改了他代码里DataGridViewProgressCell类里的Paint函数(改成根据枚举值的不同显示成功或失败的图片),然后我绑定到的数据源的实体属性(mode属性),到这一步当数据源里的mode属性更改的时候界面上的图片并不能切换,然后按照版主大大说的让数据实体实现INotifyPropertyChanged接口,成功实现了预期效果。通过这个例子发现datagridview真的好强大。。。
最后,整理一下学习到的知识点:
1、手动创建Column,将数据源实体属性手动绑定到创建的Column上
2、自定义控件列(这里要区分cell的ValueType和FormattedValueType)
3、数据源实现INotifyPropertyChanged接口(这样才能保证在数据源变更时触发控件属性的更改,进而触发界面的重新渲染等)
蒋晟 2020-02-16
  • 打赏
  • 举报
回复
设计的时候可以绑定到一个object data source,类型选择的时候选择你的实体类型,比如DataModel 到运行的时候把datagridview的数据源换成BndingList<DataModel>
lianying168000 2020-02-15
  • 打赏
  • 举报
回复
好的,我在尝试怎么用HZH_Controls的控件库实现。不得不说,在家办公效率有点低。
lianying168000 2020-02-15
  • 打赏
  • 举报
回复
我大概晓得什么错了,我测试窗体的窗体加载函数里像下面那样绑定的数据源,在从数据源映射自动映射到datagridview时,数据类型不一致导致的错误。

DataGridViewColumn column = new DataGridViewTextBoxColumn();
column.DataPropertyName = "ID";
column.Name = "编号";
dataGridView1.Columns.Add(column);

column = new DataGridViewTextBoxColumn();
column.DataPropertyName = "Name";
column.Name = "项目";
dataGridView1.Columns.Add(column);

column = new CustomColumn();
column.DataPropertyName = "Mode";
column.Name = "显示模式";
dataGridView1.Columns.Add(column);

DataModel model = new DataModel
{
ID = "TG1",
Name = "Illegal Response非法响应错误",
Mode = ShowMode.No,
};
lianying168000 2020-02-15
  • 打赏
  • 举报
回复
引用 3 楼 蒋晟 的回复:
忘记说了,你在外面改了那个数据源的Mode属性,需要自己去触发INotifyPropertyChanged.PropertyChanged事件不然后面不会有链式反应修改控件的Mode属性

我写的总是报下面这个错:


不怎么会写CustomCell这一块,Value、FormatedValue搞得头晕。。。
我还没写到触发INotifyPropertyChanged.PropertyChanged事件,现在一运行就报上面的错误,在DataGridView控件的DataError事件里能捕捉到。我写的code如下,哪里出问题了?
    
// 自定义单元格
public class CustomCell : DataGridViewCell
{
public override Type ValueType => typeof(CustomControl);

public override Type FormattedValueType {
get { return typeof(CustomCell); }
}

protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle,
TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter,
DataGridViewDataErrorContexts context)
{
if ((context & DataGridViewDataErrorContexts.ClipboardContent) != 0)
{
return this.Description;
}

object obj2 = base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter,
formattedValueTypeConverter, context);
if ((obj2 == null) && (cellStyle.NullValue == null))
{
return null;
}

return obj2;
}

public object Description { get; set; }
}

// 自定义列
public class CustomColumn : DataGridViewColumn
{
public CustomColumn() : base(new CustomCell()){

}
}

// 定义的复合控件
public partial class CustomControl : UserControl
{
private ShowMode currentMode;
public CustomControl()
{
InitializeComponent();
}
public ShowMode Mode
{
get { return currentMode; }
set
{
currentMode = value;
if (currentMode == ShowMode.No)
{
this.pictureBox1.Hide();
this.pictureBox2.Hide();
this.pictureBox3.Hide();
}
else if (currentMode == ShowMode.Progressing)
{
this.pictureBox1.Show();
this.pictureBox2.Hide();
this.pictureBox3.Hide();
}
else if (currentMode == ShowMode.Success)
{
this.pictureBox1.Hide();
this.pictureBox2.Show();
this.pictureBox3.Hide();
}
else if (currentMode == ShowMode.Fail)
{
this.pictureBox1.Hide();
this.pictureBox2.Hide();
this.pictureBox3.Show();
}
}
}
}

// mode枚举:无,执行中,执行成功,执行失败,用于指示自定义复合控件显示对应图标
public enum ShowMode
{
No,
Progressing,
Success,
Fail,
}
// 实体对象
public class DataModel : INotifyPropertyChanged
{
private ShowMode mode;
public string ID { get; set; }
public string Name { get; set; }

public ShowMode Mode
{
get { return mode;}
set
{
mode = value;
OnPropertyChanged("Mode");
}
}

public List<DataModel> Childrens { get; set; }

public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
蒋晟 2020-02-14
  • 打赏
  • 举报
回复
忘记说了,你在外面改了那个数据源的Mode属性,需要自己去触发INotifyPropertyChanged.PropertyChanged事件不然后面不会有链式反应修改控件的Mode属性
lianying168000 2020-02-14
  • 打赏
  • 举报
回复
好的 我先尝试下 多谢🙏
蒋晟 2020-02-14
  • 打赏
  • 举报
回复
无法修改控件类型。不过你可以做成复合控件。就是做一个User Control然后往里面拖控件。之后把这个作为你的datagridview的特定列的控件模板。参考MSDN上How to: Host Controls in Windows Forms DataGridView Cells这篇文章。 然后给你的Row对应的数据源加一列,叫做Mode,用来控制复合控件里哪些控件应该显示,哪些控件需要隐藏,或者哪些控件需要移动。你在外面控制就去改那个值。给你的复合控件也加一个Mode属性,在列属性里把你的User Control的Mode绑定到Row的Mode。比如你可以这么写你的复合控件的Mode属性 int Mode{ get(){return currentMode;} set(int Value) {currentMode=value; if(currentMode==1} { this.picturebox1.Hide() } if(currentMode==2} { this.picturebox1.Show() } } 你的数据源的修改并不会自动更新你的单元格,除非你在数据源上提供绑定支持。你每个Row的数据源需要实现INotifyPropertyChanged。你的数据源需要捕捉每个项的INotifyPropertyChanged,把PropertyChanged事件转换成datagridview能够理解的ListChanged事件(ListChangedType =ItemChanged)。一个简单的做法是直接用BindingList<T>来做datagridview的数据源,这里T是你的实现了INotifyPropertyChanged的Row数据类型。

8,834

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 组件/控件开发
社区管理员
  • 组件/控件开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧