2016-08-05 233 views
2

到目前爲止,我使用Xceed屬性網格和AutoGenerateProperties="True",並使用[Browsable(false)]屬性指定不想顯示哪些屬性。xceed propertygrid:在自定義屬性定義集之間進行選擇

現在我有一個情況,我只需要顯示屬性的一個子集,具體取決於其他屬性的值。

我認爲答案是使用PropertyDefinitions,如here所示。

但該示例僅顯示如何實現將用於每個檢查對象的一組PropertyDefinitions

您有提示或示例說明如何定義多組PropertyDefinitions並選擇何時使用它們?

回答

2

對不起,這是一個相當長的答案。我也曾經使用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; 
      } 
     } 
    } 
}