c# - xceed属性网格: choose between sets of custom propertydefinitions

标签 c# wpf propertygrid xceed

到目前为止,我将 Xceed propertygrid 与 AutoGenerateProperties="True" 一起使用,并使用 [Browsable(false)] 指定我不想显示的属性> 属性。

现在我有一个案例,我需要仅显示属性的子集,具体取决于其他属性的值。

我认为答案是使用PropertyDefinitions,如图here .

但该示例仅展示了如何实现将用于每个检查对象的一组 PropertyDefinitions

您是否有关于如何定义多组 PropertyDefinitions 并选择何时使用它们的提示或示例?

最佳答案

抱歉,这是一个相当冗长的答案。我也曾经使用 AutoGenerateProperties="True" 但我也遇到了类似的问题。

我得到的解决方案是按照您的建议填充PropertyDefinition。我以编程方式执行此操作,因为我最终遇到了一些相当特殊的情况,需要根据某处集合的内容动态创建属性。我注意到的一件事是,即使通过以编程方式检查我的类来模拟 AutoGenerateProperties="True" 功能,我的解决方案也比他们的解决方案快得多。

为了按照您的要求处理可见性,我必须创建自己的 Attribute 以使项目在 PropertyGrid 中不可见。

public class VisibilityAttribute : Attribute
{
    public Visibility Visibility { get; private set; }

    public VisibilityAttribute(Visibility visibility)
    {
        this.Visibility = visibility;
    }
}

我的项目中可以选择的每个项目都有自己的 PropertySetBase 类实现,该类具有如下属性定义:

[Category("Appearance"), LocalisedProperty(typeof(PropertySetBase), "LocalBackground", "LocalBackgroundDescription"), Editor(typeof(OptionalBrushEditor), typeof(OptionalBrushEditor)),
        PropertyOrder(0)]
    public virtual OptionalProperty<Brush> LocalBackground { get; set; }

以及处理 currentPropertySelection 集合中的 PropertySetBase 的逻辑。

private void PreparePropertyGrid()
{
    PropertyDefinitionCollection propertyDefinitions = new PropertyDefinitionCollection();

    // This is how I determine 
    var mainPropertySet = this.currentPropertySelection.FirstOrDefault();

    if (mainPropertySet != null)
    {
        var properties = TypeDescriptor.GetProperties(mainPropertySet.GetType());
        // Allowing for multiple selection, if on further iterations through the selected items we will remove properties that do not exist in both PropertySets
        bool firstIteration = true;

        foreach (var x in this.currentPropertySelection)
        {
            foreach (var p in properties.Cast<PropertyDescriptor>())
            {
                if (!firstIteration)
                {
                    // Perhaps we should be checking a little more safely for TargetProperties but if the collection is empty we have bigger problems.
                    var definition = propertyDefinitions.FirstOrDefault(d => string.Equals(d.TargetProperties[0] as string, p.Name, StringComparison.Ordinal));

                    // Someone in the selection does not have this property so we can ignore it.
                    if (definition == null)
                    {
                        continue;
                    }

                    // If this item doesn't have the property remove it from the display collection and proceed.
                    var localProperty = x.GetType().GetProperty(p.Name);
                    if (localProperty == null)
                    {
                        propertyDefinitions.Remove(definition);
                        continue;
                    }

                    // There is actually no point in proceeding if this is not the first iteration and we have checked whether the property exists.
                    continue;
                }

                string category = p.Category;
                string description = p.Description;
                string displayName = p.DisplayName ?? p.Name;
                int? displayOrder = null;
                bool? isBrowsable = p.IsBrowsable;
                bool? isExpandable = null;

                var orderAttribute = p.Attributes[typeof(PropertyOrderAttribute)] as PropertyOrderAttribute;
                if (orderAttribute != null)
                {
                    displayOrder = orderAttribute.Order;
                }

                var expandableAttribute = p.Attributes[typeof(ExpandableObjectAttribute)] as ExpandableObjectAttribute;
                if (expandableAttribute != null)
                {
                    isExpandable = true;
                }

                propertyDefinitions.Add(new PropertyDefinition
                {
                    Category = category,
                    Description = description,
                    DisplayName = displayName,
                    DisplayOrder = displayOrder,
                    IsBrowsable = isBrowsable,
                    IsExpandable = isExpandable,
                    TargetProperties = new[] { p.Name },
                });
            }
        }

        firstIteration = false;

        this.propertyGrid.PropertyDefinitions = propertyDefinitions;
    }
}

当涉及到实际显示/隐藏属性时,我执行了以下操作:

public void UpdateProperties(Tuple<string, bool?, Visibility?>[] newPropertyStates)
{
    // Note this currently works under the assumption that an Item has to be selected in order to have a value changed.
    this.suppressPropertyUpdates = true;

    foreach (var property in newPropertyStates)
    {
        string propertyName = property.Item1;

        string[] splits = propertyName.Split('.');
        if (splits.Length == 1)
        {
            this.propertyGrid.Properties.OfType<PropertyItem>()
                                        .Where(p => string.Equals(p.PropertyDescriptor.Name, propertyName, StringComparison.Ordinal))
                                        .Map(p =>
            {
                if (property.Item2.HasValue)
                {
                    p.IsEnabled = property.Item2.Value;
                }

                if (property.Item3.HasValue)
                {
                    p.Visibility = property.Item3.Value;
                }
            });

        }
        else // We currently don't expect to go any lower than 1 level.
        {
            var parent = this.propertyGrid.Properties.OfType<PropertyItem>()
                                                     .Where(p => string.Equals(p.PropertyDescriptor.Name, splits[0], StringComparison.Ordinal))
                                                     .FirstOrDefault();

            if (parent != null)
            {
                parent.Properties.OfType<PropertyItem>()
                                 .Where(p => string.Equals(p.PropertyDescriptor.Name, splits[1], StringComparison.Ordinal))
                                 .Map(p =>
                {
                    if (property.Item2.HasValue)
                    {
                        p.IsEnabled = property.Item2.Value;
                    }
                    if (property.Item3.HasValue)
                    {
                        p.Visibility = property.Item3.Value;
                    }
                });
            }
        }
    }

    this.suppressPropertyUpdates = false;
}

然后在PreparePropertyItem 事件处理程序中,我检查VisibilityAttribute 并相应地更新属性项。

void PropertyGrid_PreparePropertyItem(object sender, PropertyItemEventArgs e)
{
    foreach (var x in this.currentPropertySelection)
    {
        // If we are in read-only mode do not allow the editing of any property.
        if (this.IsReadOnly)
        {
            e.PropertyItem.IsEnabled = false;
        }

        string propertyName = ((PropertyItem)e.PropertyItem).PropertyDescriptor.Name;
        PropertyInfo property = x.GetType().GetProperty(propertyName);
        var propertyItem = e.Item as PropertyItem;

        // If the property doesn't exist then check to see if it is on an expandable item.
        if (property == null)
        {
            property = propertyItem.Instance.GetType().GetProperty(propertyName);
        }

        bool hasProperty = property != null;

        if (hasProperty)
        {
            var browsableAttribute = property.GetCustomAttribute<BrowsableAttribute>(true);
            if (browsableAttribute != null &&
                !browsableAttribute.Browsable)
            {
                e.PropertyItem.Visibility = Visibility.Collapsed;
                e.Handled = true;
                break;
            }

            var visibilityAttribute = property.GetCustomAttribute<VisibilityAttribute>(true);
            if (visibilityAttribute != null)
            {
                e.PropertyItem.Visibility = visibilityAttribute.Visibility;
                e.Handled = true;
            }

            var independentAttribute = property.GetCustomAttribute<IndependentAttribute>(true);
            // If a property is marked as being independent then we do not allow editing if multiple items are selected
            if (independentAttribute != null &&
                this.currentPropertySelection.Length > 1)
            {
                e.PropertyItem.IsEnabled = false;
                e.Handled = true;
                break;
            }
        }
    }
}

关于c# - xceed属性网格: choose between sets of custom propertydefinitions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38783975/

相关文章:

c# - 什么是 "DateTime?"而不是 C# 中的 DateTime?

WPF ToggleButton 绑定(bind) IsChecked 禁用时

c# - 在具有多次运行的 WPF Textblock 中,如何将样式应用于特定的样式?

.net - 是否可以向 ExpandoObject 实例的生成成员添加属性?

c# - PropertyGrid UITypeEditor 禁用单元格编辑

c# - 如何直接在 MySQL 中更新 magento stock

c# - ASP.NET Core 属性路由

c# - 为异步代码选择 Task 或 void 方法

wpf - Datagrid (WPF) 以编程方式设置列样式(不是 xaml)

c# - 如何在不使用类别的情况下在属性网格中添加组?