我的World
课程中有一个属性如下:
public Vec2 Gravity
{
get {
Console.WriteLine("Getting gravity!");
return GetGravity();
}
set {
Console.WriteLine("Setting gravity!");
SetGravity(value);
}
}
“获得引力!”当PropertyGrid
尝试读取值时,字符串按预期显示,但当我尝试更改重力矢量并按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
成为一个类,但我现在无法真正测试,因为我的应用程序非常依赖于它是一个结构。
答案 0 :(得分:1)
我认为属性网格直接在Vec2对象上设置属性(即X
和Y
属性)。
答案 1 :(得分:1)
它正在更改Vec2
的X和Y属性,因为这就是您要设置的内容。更改这些属性时,如果您将其转换为代码,我猜它正在调用Gravity.X = value;
,当您考虑它时,Get
上的Gravity
实际上是Set
,并且然后在Vec2.X
上Set
。
使用您当前的代码,为了输入Gravity
的{{1}},您需要明确地将其更改为新的Vec2
对象。
编辑:显然,[NotifyParentProperty(true)]
并不好,清除了我的不确定性。
答案 2 :(得分:1)
以下是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分配值。您添加CanConvertFrom的事实指示网格parentGridEntry.IsValueEditable现在为真。
答案 3 :(得分:0)
答案取决于您如何编辑该属性:
如果您通过直接在Gravity
属性中键入文本来编辑属性,那么我怀疑您的TypeConverter
将被调用,并且应该调用Gravity
属性的setter。这假设Gravity属性甚至在属性网格中显示为可编辑,我怀疑它应该是。
如果您通过展开属性(点击小+
符号)然后直接设置其X
或Y
属性来编辑属性,那么Gravity
属性的setter将会永远不会被打电话只有X
和Y
属性才能调用他们的 setter。
通常,在大多数框架中,复杂属性不可设置。它们通常仅通过其子属性设置。在这种情况下,我认为将整个属性设置为合理是合理的,因为它似乎是一种常见的操作。这只是一种设计选择,无论哪种方式都不是对的。
答案 4 :(得分:0)
在托管C ++中:
[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; }
}
};