如何在 PropertyGrid 中一键更改布尔属性
How do I change boolean properties with one click in PropertyGrid
我们有一个 windows 表单 PropertyGrid
用于显示所有属性。我们在 Boolean 属性 上绘制了一个复选框,它会根据值自行选中并取消选中。这一切都很好。
问题是,用户想通过单击更改复选框值,而 属性 网格通过双击更改它,我想不出一种方法来处理点击或更改 属性 当 属性 类型为布尔值时单击的值。
如何通过单击更改 属性 值?
PropertyGrid
内部有一些方法,当您单击其 PropertyGridView
内部控件时,我们可以通过反射使用它们来获取鼠标下方的 GridItem
。
在下面的代码中,我处理了鼠标点击其 PropertyGridView
控件并检查鼠标位置下的项目是否为布尔值 属性,我反转了它的值。该事件将针对 属性 的标签以及 属性 编辑器的图标区域触发:
PropertyGrid
using System;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
public class ExPropertyGrid : PropertyGrid
{
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
var grid = this.Controls[2];
grid.MouseClick += grid_MouseClick;
}
void grid_MouseClick(object sender, MouseEventArgs e)
{
var grid = this.Controls[2];
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var invalidPoint = new Point(-2147483648, -2147483648);
var FindPosition = grid.GetType().GetMethod("FindPosition", flags);
var p = (Point)FindPosition.Invoke(grid, new object[] { e.X, e.Y });
GridItem entry = null;
if (p != invalidPoint) {
var GetGridEntryFromRow = grid.GetType()
.GetMethod("GetGridEntryFromRow", flags);
entry = (GridItem)GetGridEntryFromRow.Invoke(grid, new object[] { p.Y });
}
if (entry != null && entry.Value != null) {
object parent;
if (entry.Parent != null && entry.Parent.Value != null)
parent = entry.Parent.Value;
else
parent = this.SelectedObject;
if (entry.Value != null && entry.Value is bool) {
entry.PropertyDescriptor.SetValue(parent,!(bool)entry.Value);
this.Refresh();
}
}
}
}
在PropertyGrid中绘制CheckBox
public class MyBoolEditor : UITypeEditor
{
public override bool GetPaintValueSupported
(System.ComponentModel.ITypeDescriptorContext context)
{ return true; }
public override void PaintValue(PaintValueEventArgs e)
{
var rect = e.Bounds;
rect.Inflate(1, 1);
ControlPaint.DrawCheckBox(e.Graphics, rect, ButtonState.Flat |
(((bool)e.Value) ? ButtonState.Checked : ButtonState.Normal));
}
}
Class 截图中使用
public class Model
{
public int Property1 { get; set; }
[Editor(typeof(MyBoolEditor), typeof(UITypeEditor))]
public bool Property2 { get; set; }
[TypeConverter(typeof(ExpandableObjectConverter))]
public Model Property3 { get; set; }
}
最佳答案使用反射获取鼠标下的GridItem。但是,我看不出这样做有什么意义,因为请求一个专用的 GridItem 就足够了。这是我对 MouseClick 的实现:
void grid_MouseClick(object sender, MouseEventArgs e)
{
GridItem entry = SelectedGridItem;
if (entry != null && entry.Value != null && entry.Value is bool b)
{
var obj = SelectedObjects.Length == 1 ? SelectedObject : SelectedObjects;
entry.PropertyDescriptor.SetValue(obj, !b);
}
}
我想发表评论,但代表还不够高。
接受的答案效果很好。但是,如前所述,代码不会触发 PropertyValueChanged 事件。
添加对 OnPropertyValueChanged 的调用会触发 PropertyValueChanged 事件。
entry.PropertyDescriptor.SetValue(parent, !(bool)entry.Value);
this.Refresh();
base.OnPropertyValueChanged(null);
然后在 PropertyValueChanged 事件代码中就可以访问已经更改的自定义对象了。
要将更改的 属性 传达回表单,请在自定义对象中创建一些属性,并将 Browsable 设置为 false,这样它们就不会出现在 PropertyGrid 中。
[Browsable(false)]
public string changedParent { get; set; }
[Browsable(false)]
public string changedLabel { get; set; }
[Browsable(false)]
public string changedValue { get; set; }
在表单顶部 class 创建这个静态 属性
public partial class Form1 : Form
{
private static Form1 form = null;
在 Form1 的构造函数中 link 形成这个。
public Form1()
{
InitializeComponent();
..
..
form = this;
在触发 OnPropertyValueChanged 之前返回 grid_MouseClick 保存更改的 属性 信息。
entry.PropertyDescriptor.SetValue(parent, !(bool)entry.Value);
this.Refresh();
form.sh.changedParent = entry.Parent.Label;
form.sh.changedLabel = entry.Label;
form.sh.changedValue = entry.Value.ToString();
base.OnPropertyValueChanged(null);
现在,在 PropertyValueChanged 事件代码中,您可以确定更改了哪个 属性。
form.customobject.changedParent
form.customobject.changedLabel
form.customobject.changedValue
我们有一个 windows 表单 PropertyGrid
用于显示所有属性。我们在 Boolean 属性 上绘制了一个复选框,它会根据值自行选中并取消选中。这一切都很好。
问题是,用户想通过单击更改复选框值,而 属性 网格通过双击更改它,我想不出一种方法来处理点击或更改 属性 当 属性 类型为布尔值时单击的值。
如何通过单击更改 属性 值?
PropertyGrid
内部有一些方法,当您单击其 PropertyGridView
内部控件时,我们可以通过反射使用它们来获取鼠标下方的 GridItem
。
在下面的代码中,我处理了鼠标点击其 PropertyGridView
控件并检查鼠标位置下的项目是否为布尔值 属性,我反转了它的值。该事件将针对 属性 的标签以及 属性 编辑器的图标区域触发:
PropertyGrid
using System;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
public class ExPropertyGrid : PropertyGrid
{
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
var grid = this.Controls[2];
grid.MouseClick += grid_MouseClick;
}
void grid_MouseClick(object sender, MouseEventArgs e)
{
var grid = this.Controls[2];
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var invalidPoint = new Point(-2147483648, -2147483648);
var FindPosition = grid.GetType().GetMethod("FindPosition", flags);
var p = (Point)FindPosition.Invoke(grid, new object[] { e.X, e.Y });
GridItem entry = null;
if (p != invalidPoint) {
var GetGridEntryFromRow = grid.GetType()
.GetMethod("GetGridEntryFromRow", flags);
entry = (GridItem)GetGridEntryFromRow.Invoke(grid, new object[] { p.Y });
}
if (entry != null && entry.Value != null) {
object parent;
if (entry.Parent != null && entry.Parent.Value != null)
parent = entry.Parent.Value;
else
parent = this.SelectedObject;
if (entry.Value != null && entry.Value is bool) {
entry.PropertyDescriptor.SetValue(parent,!(bool)entry.Value);
this.Refresh();
}
}
}
}
在PropertyGrid中绘制CheckBox
public class MyBoolEditor : UITypeEditor
{
public override bool GetPaintValueSupported
(System.ComponentModel.ITypeDescriptorContext context)
{ return true; }
public override void PaintValue(PaintValueEventArgs e)
{
var rect = e.Bounds;
rect.Inflate(1, 1);
ControlPaint.DrawCheckBox(e.Graphics, rect, ButtonState.Flat |
(((bool)e.Value) ? ButtonState.Checked : ButtonState.Normal));
}
}
Class 截图中使用
public class Model
{
public int Property1 { get; set; }
[Editor(typeof(MyBoolEditor), typeof(UITypeEditor))]
public bool Property2 { get; set; }
[TypeConverter(typeof(ExpandableObjectConverter))]
public Model Property3 { get; set; }
}
最佳答案使用反射获取鼠标下的GridItem。但是,我看不出这样做有什么意义,因为请求一个专用的 GridItem 就足够了。这是我对 MouseClick 的实现:
void grid_MouseClick(object sender, MouseEventArgs e)
{
GridItem entry = SelectedGridItem;
if (entry != null && entry.Value != null && entry.Value is bool b)
{
var obj = SelectedObjects.Length == 1 ? SelectedObject : SelectedObjects;
entry.PropertyDescriptor.SetValue(obj, !b);
}
}
我想发表评论,但代表还不够高。 接受的答案效果很好。但是,如前所述,代码不会触发 PropertyValueChanged 事件。
添加对 OnPropertyValueChanged 的调用会触发 PropertyValueChanged 事件。
entry.PropertyDescriptor.SetValue(parent, !(bool)entry.Value);
this.Refresh();
base.OnPropertyValueChanged(null);
然后在 PropertyValueChanged 事件代码中就可以访问已经更改的自定义对象了。
要将更改的 属性 传达回表单,请在自定义对象中创建一些属性,并将 Browsable 设置为 false,这样它们就不会出现在 PropertyGrid 中。
[Browsable(false)]
public string changedParent { get; set; }
[Browsable(false)]
public string changedLabel { get; set; }
[Browsable(false)]
public string changedValue { get; set; }
在表单顶部 class 创建这个静态 属性
public partial class Form1 : Form
{
private static Form1 form = null;
在 Form1 的构造函数中 link 形成这个。
public Form1()
{
InitializeComponent();
..
..
form = this;
在触发 OnPropertyValueChanged 之前返回 grid_MouseClick 保存更改的 属性 信息。
entry.PropertyDescriptor.SetValue(parent, !(bool)entry.Value);
this.Refresh();
form.sh.changedParent = entry.Parent.Label;
form.sh.changedLabel = entry.Label;
form.sh.changedValue = entry.Value.ToString();
base.OnPropertyValueChanged(null);
现在,在 PropertyValueChanged 事件代码中,您可以确定更改了哪个 属性。
form.customobject.changedParent
form.customobject.changedLabel
form.customobject.changedValue