C # PropertyGrid: изменение свойств не работает? - PullRequest
1 голос
/ 18 января 2010

У меня есть свойство в моем World классе, которое выглядит так:

    public Vec2 Gravity
    {
        get {
            Console.WriteLine("Getting gravity!");
            return GetGravity(); 
        }
        set {
            Console.WriteLine("Setting gravity!");
            SetGravity(value); 
        }
    }

«Получение гравитации!» Строка отображается, как и ожидалось, когда PropertyGrid пытается прочитать значение, но когда я пытаюсь изменить вектор гравитации и нажать клавишу ввода, ничего не происходит. Почему нет?


Мой 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 исправляет это в случае с индивидуальными свойствами ??


I думаю ответ состоит в том, что Vec2 является структурой, поэтому, когда World возвращает вектор Gravity, он передает его по значению, а затем копирует изменен, а не фактический Gravity вектор.

Решение, я думаю, состоит в том, чтобы сохранить методы CanConvertFrom и ConvertFrom на месте. Я предполагаю, что они заставляют его работать, потому что они изменяют строковое представление вектора гравитации, а затем , что в свою очередь обновляет фактический вектор гравитации. Это или создание Vec2 класса должно работать, но сейчас я не могу это проверить, потому что мое приложение очень зависит от того, является ли оно структурой.

Ответы [ 5 ]

1 голос
/ 18 января 2010

Вот код для 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 является типом значения, поэтому флаг имеет значение true. В сетке экземпляр vec2 является копией вашей структуры, поэтому ваш оригинал еще не был изменен, но когда parentGridEntry.PropertyValue = obj; вызывается, затем значение присваивается через PropertyDescriptor свойства Gravity в вашем классе контейнера. Тот факт, что вы добавили CanConvertFrom, указывает сетке, что parentGridEntry.IsValueEditable теперь имеет значение true.

1 голос
/ 18 января 2010

Я думаю, что сетка свойств задает свойства непосредственно для объекта Vec2 (т.е. свойства X и Y).

1 голос
/ 18 января 2010

Это изменение свойств X и Y Vec2, потому что это то, что вы устанавливаете. При изменении этих свойств, если вы переводите его в код, я предполагаю, что он вызывает Gravity.X = value;, что, если подумать, на самом деле означает Get на Gravity, а затем Set на Vec2.X.

С вашим текущим кодом, чтобы ввести Set из Gravity, вам необходимо явно изменить его на новый Vec2 объект.

РЕДАКТИРОВАТЬ: И, очевидно, [NotifyParentProperty(true)] не годится, проясняя мою неуверенность.

0 голосов
/ 02 ноября 2010

В управляемом 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; }
    }
};
0 голосов
/ 18 января 2010

Ответ зависит от того, как вы редактируете свойство:

Если вы редактируете свойство, вводя текст непосредственно в свойство Gravity, то я подозреваю, что будет вызван ваш TypeConverter и должен быть вызван установщик свойства Gravity. Это предполагает, что свойство Gravity даже отображается как редактируемое в сетке свойств, что, как я подозреваю, должно.

Если вы отредактируете свойство, развернув его (щелкнув по маленькому знаку +), а затем непосредственно установив его свойство X или Y, средство установки свойства Gravity никогда не будет вызываться. Только свойства X и Y будут вызывать их сеттеры.

В общем случае и в большинстве структур сложные свойства не устанавливаются. Они часто устанавливаются только через свои подвойства. В этом случае я думаю, что было бы разумно установить все свойства, так как кажется, что это будет обычная операция. Это просто выбор дизайна, и ни в коем случае нельзя делать это правильно.

...