C#PropertyGrid:更改属性不起作用?
我在我的C#PropertyGrid:更改属性不起作用?,c#,winforms,propertygrid,C#,Winforms,Propertygrid,我在我的World类中有一个如下所示的属性: public Vec2 Gravity { get { Console.WriteLine("Getting gravity!"); return GetGravity(); } set { Console.WriteLine("Setting gravity!"); SetGravity(
World
类中有一个如下所示的属性:
public Vec2 Gravity
{
get {
Console.WriteLine("Getting gravity!");
return GetGravity();
}
set {
Console.WriteLine("Setting gravity!");
SetGravity(value);
}
}
当PropertyGrid
尝试读取值时,“Getting gravity!”字符串按预期显示,但当我尝试更改重力向量并按enter键时,什么也没有发生。为什么不呢
我的
Vec2
类具有以下属性:
public float X
{
get
{
return x;
}
set
{
x = value;
}
}
public float Y
{
get
{
return y;
}
set
{
y = value;
}
}
在网格上可见,这得益于:
public class Vec2Converter : ExpandableObjectConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, System.Type destinationType)
{
if (destinationType == typeof(Vec2)) return true;
else return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
{
if (destinationType == typeof(string) && value is Vec2)
{
Vec2 vec = (Vec2)value;
return string.Format("{0}, {1}", vec.X, vec.Y);
}
else return base.ConvertTo(context, culture, value, destinationType);
}
}
我刚刚将这两种方法添加到
Vec2Converter
中,现在它可以工作了:
public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType)
{
if (sourceType == typeof(string)) return true;
else return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
try
{
string strVal = value as string;
var parts = strVal.Split(',');
float x = float.Parse(parts[0]);
float y = float.Parse(parts[1]);
return new Vec2(x, y);
}
catch
{
throw new ArgumentException("Can not convert '" + (string)value + "'to type Vec2");
}
}
else return base.ConvertFrom(context, culture, value);
}
它通过更改字符串表示和单个属性来工作。为什么thix会针对具有单个属性的案例进行修复
我认为的答案是
Vec2
是一个结构,因此当World
返回Gravity
向量时,它按值传递它,然后更改副本,而不是实际的Gravity
向量
我认为解决方案是要么保留
CanConvertFrom
方法,要么保留ConvertFrom
方法。我假设它们能够工作,因为它们修改了重力向量的字符串表示,然后又更新了实际的重力向量。这或者说让Vec2
成为一个类应该是可行的,但我现在不能真正测试它,因为我的应用程序非常依赖于它是一个结构。答案取决于你如何编辑属性:
如果您通过直接在Gravity
属性中键入文本来编辑属性,那么我怀疑将调用TypeConverter
,并且应该调用Gravity
属性的setter。这是假设重力特性甚至在特性栅格中显示为可编辑的,我认为它应该这样做
如果通过展开属性(单击小的+
符号),然后直接设置其X
或Y
属性来编辑属性,则将永远不会调用重力
属性的设置器。只有X
和Y
属性将调用它们的setter
一般来说,在大多数框架中,复杂属性是不可设置的。它们通常仅通过其子属性进行设置。在这种情况下,我认为设置整个属性是合理的,因为它似乎是一个常见的操作。这只是一种设计选择,无论哪种方式都没有错。我认为属性网格直接在Vec2对象上设置属性(即
X
和Y
属性)。它正在更改Vec2
的X和Y属性,因为这就是您要设置的。当更改这些属性时,如果将其转换为代码,我猜它正在调用Gravity.X=value
,当你考虑它时,它实际上是一个重力上的获取,然后是向量2.X上的设置
使用当前代码,要输入重力的集合
,需要将其显式更改为新的Vec2
对象
编辑:显然,[NotifyParentProperty(true)]
不好,这消除了我的不确定性。以下是PropertyDescriptorGridEntry.SetPropertyValueCore的代码:
protected void SetPropertyValueCore(object obj, object value, bool doUndo)
{
if (this.propertyInfo != null)
{
Cursor current = Cursor.Current;
try
{
Cursor.Current = Cursors.WaitCursor;
object component = obj;
if (component is ICustomTypeDescriptor)
{
component = ((ICustomTypeDescriptor) component).GetPropertyOwner(this.propertyInfo);
}
bool flag = false;
if (this.ParentGridEntry != null)
{
Type propertyType = this.ParentGridEntry.PropertyType;
flag = propertyType.IsValueType || propertyType.IsArray;
}
if (component != null)
{
this.propertyInfo.SetValue(component, value);
if (flag)
{
GridEntry parentGridEntry = this.ParentGridEntry;
if ((parentGridEntry != null) && parentGridEntry.IsValueEditable)
{
parentGridEntry.PropertyValue = obj;
}
}
}
}
finally
{
Cursor.Current = current;
}
}
}
在您的例子中,Vec2是一个值类型,所以flag为true。在网格中,vec2实例是结构的副本,因此原始实例尚未修改,但当parentGridEntry.PropertyValue=obj;调用,然后通过容器类中Gravity属性的PropertyDescriptor指定该值。事实上,您添加C++转换命令来指示PrPrGrIDeNo.IsValueEdvest-Grand的网格现在是真的。
[TypeConverter(ExpandableObjectConverter::typeid)]
public ref struct Vector3
{
float x, y, z;
property float X
{
float get() { return x; }
void set(float value) { x = value; }
}
property float Y
{
float get() { return y; }
void set(float value) { y = value; }
}
property float Z
{
float get() { return z; }
void set(float value) { z = value; }
}
};
我不认为您实际上在更改属性,否则您必须点击控制台;陈述在那里放一个断点,它击中了吗?@Lwoodyii:不,这是我的观点。它一点也没有击中它。不明白为什么。。。没有什么Commit()
或Save()
我必须做的事情了吗?@Jader:实际的Main()
方法?不确定这有多大帮助,但已经发布了。在windows应用程序上不需要这样做,在Vec2 vec=(Vec2)值上设置断点如何;然后踏进兔子洞,跟着兔子洞走。@Jader:Err。。winforms
标记和PropertyGrid
的使用并没有泄露它?很好的调用。它确实在改变Vec2
,而没有调用Gravity
setter。但是为什么呢?我该怎么解决呢?如果我知道的话:-)几天前我遇到了一个非常类似的问题,但这对我来说还不够重要,无法找到解决方案…@马克,用你所拥有的,你无法让它调用setter,因为它不需要调用setter。当它只想设置它的一个子属性时,VS创建一个新的Vec3
实例有什么意义?要使它始终调用它,您必须去掉ExpandableObjectConverter
,并使Gravity
属性仅通过在属性网格中键入“123456”
即可编辑。设置X和Y(子)属性而不是重力属性的问题到底在哪里?你试过把Vec2变成一个结构吗?我不知道这是否可行,但如果这是你的选择。。。尽管您应该删除此中的settercase@Martin:Vec2已经是一个结构。问题是编辑子属性会编辑Vec2
,它是由Gravity
getter返回的,它没有引用myWorld
对象上的\u Gravity
变量。i、 例如,更改X/Y属性是在做一些事情,但是这些更改会立即被丢弃,而且毫无用处@艾隆:这就是它在做的事情(创建/复制一个新实例)——灯亮了——这一定是因为Vec2
是一个结构体。在l