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返回的,它没有引用my
World
对象上的
\u Gravity
变量。i、 例如,更改X/Y属性是在做一些事情,但是这些更改会立即被丢弃,而且毫无用处@艾隆:这就是它在做的事情(创建/复制一个新实例)——灯亮了——这一定是因为
Vec2
是一个结构体。在l