C#PropertyGrid:更改属性不起作用?

时间:2010-01-17 23:57:19

标签: c# winforms propertygrid

我的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向量。

我认为解决方案要么保持CanConvertFromConvertFrom方法。我假设那些使它工作,因为他们修改了重力矢量的字符串表示,然后 反过来更新实际的重力矢量。那个,或者让Vec2成为一个类,但我现在无法真正测试,因为我的应用程序非常依赖于它是一个结构。

5 个答案:

答案 0 :(得分:1)

我认为属性网格直接在Vec2对象上设置属性(即XY属性)。

答案 1 :(得分:1)

它正在更改Vec2的X和Y属性,因为这就是您要设置的内容。更改这些属性时,如果您将其转换为代码,我猜它正在调用Gravity.X = value;,当您考虑它时,Get上的Gravity实际上是Set,并且然后在Vec2.XSet

使用您当前的代码,为了输入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属性甚至在属性网格中显示为可编辑,我怀疑它应该是。

如果您通过展开属性(点击小+符号)然后直接设置其XY属性来编辑属性,那么Gravity属性的setter将会永远不会被打电话只有XY属性才能调用他们的 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; }
    }
};