编辑多个对象时属性在propertyGrid中的C#条件外观

本文关键字:中的 propertyGrid 条件 外观 属性 对象 编辑 | 更新日期: 2023-09-27 18:29:29

刚刚偶然发现了propertyGrid及其强大功能!然而,我有一项任务,我找不到如何处理它:

我有一个有类型的类。根据类型,它具有不同的可用属性。为了简单起见,我将它保存在一个类中(而不是多个继承类)(有十种类型,但它们大多具有相同的属性)。

例如,我有一个类MapObject,它的字符串类型可以等于"播放器"或"敌人"。对于"敌人",使用属性"名称",但对于"玩家",属性为空(未使用)。

当我选择两个对象时,其中一个是类型"玩家",另一个是"敌人",我希望属性"名称"只对"敌人"计数"。因此,我希望propertyGrid显示type="敌人"的对象的名称,当它(名称属性)在Grid中更改时,只将其分配给"敌人"类型的对象。

这样做可能吗?

编辑多个对象时属性在propertyGrid中的C#条件外观

根据您正在使用的PropertyGrid,切换可浏览属性可能会达到您想要的效果。关于如何在运行时做到这一点,请参阅我的答案。

如果像我一样使用Xceed PropertyGrid,那么在加载控件后仅在运行时更改Browseable属性不会有任何作用。相反,我还必须修改PropertyDefinitions集合。这里有一个扩展方法:

    /// <summary>
    /// Show (or hide) a property within the property grid.
    /// Note: if you want to initially hide the property, it may be
    /// easiest to set the Browable attribute of the property to false.
    /// </summary>
    /// <param name="pg">The PropertyGrid on which to operate</param>
    /// <param name="property">The name of the property to show or hide</param>
    /// <param name="show">Set to true to show and false to hide</param>
    public static void ShowProperty(this PropertyGrid pg, string property, bool show)
    {
        int foundAt = -1;
        for (int i=0; i < pg.PropertyDefinitions.Count; ++i)
        {
            var prop = pg.PropertyDefinitions[i];
            if (prop.Name == property)
            {
                foundAt = i;
                break;
            }
        }
        if (foundAt == -1)
        {
            if (show)
            {
                pg.PropertyDefinitions.Add(
                    new Xceed.Wpf.Toolkit.PropertyGrid.PropertyDefinition()
                    {
                        Name = property,
                    }
                );
            }
        }
        else
        {
            if (!show)
            {
                pg.PropertyDefinitions.RemoveAt(foundAt);
            }
        }
    }

如果以上内容不适用于您,那么以下内容可能会更好、更简单。它也没有像上面的代码那样使用不推荐使用的属性。。。

    public static void ShowProperty(this PropertyGrid pg, string property, bool show)
    {
        for (int i = 0; i < pg.Properties.Count; ++i)
        {
            PropertyItem prop = pg.Properties[i] as PropertyItem;
            if (prop.PropertyName == property)
            {
                prop.Visibility = show ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
                break;
            }
        }
    }

这是一种称为状态模式的设计模式。它很容易实现,而且不需要属性网格。http://www.dofactory.com/Patterns/PatternState.aspx

我用自己的自定义属性:

public class VisibilityAttribute : Attribute
{
    public bool IsVisible { get; set; }
    public VisibilityAttribute(bool isVisible)
    {
        IsVisible = isVisible;
    }
}

然后我的数据模型:

 public abstract class BaseSettings: INotifyPropertyChanged
 {
    public void SetVisibilityProperty(string propertyName, bool isVisible)
    {
        var theDescriptor = TypeDescriptor.GetProperties(this.GetType())[propertyName];
        var theDescriptorVisibilityAttribute = (VisibilityAttribute)theDescriptor.Attributes[typeof(VisibilityAttribute)];
        if (theDescriptorVisibilityAttribute == null) return;
        theDescriptorVisibilityAttribute.IsVisible = isVisible;
    }
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}
public class ThrottleSettings : BaseSettings
{
    private ThrottleType _throttleType = ThrottleType.SmartThrottle;
    [PropertyOrder(1)]
    public ThrottleType ThrottleType
    {
        get
        {
            return _throttleType;
        }
        set
        {
            if (value == ThrottleType.FullThrottle)
            {
                SetVisibilityProperty(nameof(FullThrottleTimeInMilliseconds), true);
                SetVisibilityProperty(nameof(ThumbnailThrottleTimeInMilliseconds), false);
            }
            else if (value == ThrottleType.SmartThrottle)
            {
                SetVisibilityProperty(nameof(FullThrottleTimeInMilliseconds), false);
                SetVisibilityProperty(nameof(ThumbnailThrottleTimeInMilliseconds), true);
            }
            else if (value == ThrottleType.NoThrottle)
            {
                SetVisibilityProperty(nameof(FullThrottleTimeInMilliseconds), false);
                SetVisibilityProperty(nameof(ThumbnailThrottleTimeInMilliseconds), false);
            }
            _throttleType = value;
        }
    }
    private int _fullThrottleTime = 100;
    [PropertyOrder(2)]
    [Visibility(false)]
    [Description("Specifies full throttle time (in milliseconds).")]
    public int FullThrottleTimeInMilliseconds
    {
        get
        {
            return _fullThrottleTime;
        }
        set
        {
            if (value < 0) return;
            _fullThrottleTime = value;
        }
    }
    private int _thumbnailThrottleTime = 0;
    [PropertyOrder(3)]
    [Visibility(true)]
    [Description("Specifies thumbnail throttle time (in milliseconds).")]
    public int ThumbnailThrottleTimeInMilliseconds
    {
        get
        {
            return _thumbnailThrottleTime;
        }
        set
        {
            if (value < 0) return;
            _thumbnailThrottleTime = value;
        }
    }
}

最后,我订阅了"propertyGrid_PropertyValueChanged"事件,并在那里调用我的方法:

private void _propertyGrid_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e)
    {
        RefreshVisibility(_propertyGrid.Properties);
    }

这是方法本身:

private void RefreshVisibility(IList properties)
    {
        foreach (PropertyItem property in properties)
        {
            var visibilityAttribute = GetVisibilityAttribute(property);
            if (visibilityAttribute != null)
            {
                if (visibilityAttribute.IsVisible)
                    property.Visibility = Visibility.Visible;
                else
                    property.Visibility = Visibility.Collapsed;
            }
            RefreshVisibility(property.Properties);
        }
    }