2016-08-05 27 views
2

Bis jetzt verwende ich das Xceed-Eigenschaftgrid mit AutoGenerateProperties="True" und gebe an, welche Eigenschaften ich nicht mit dem [Browsable(false)]-Attribut anzeigen möchte.xceed propertygrid: Wählen Sie zwischen den Sätzen benutzerdefinierter Eigenschaftsdefinitionen

Jetzt habe ich einen Fall, wo ich nur eine Teilmenge von Eigenschaften zeigen muss, abhängig vom Wert einer anderen Eigenschaft.

Ich denke, die Antwort ist PropertyDefinitions zu verwenden, wie gezeigt here.

Aber das Beispiel zeigt nur, wie einen einzigen Satz von PropertyDefinitions zu implementieren, die für jedes untersuchte Objekt verwendet werden.

Haben Sie einen Hinweis oder ein Beispiel, wie ich mehrere Sätze von PropertyDefinitions definieren und entscheiden, wann sie verwendet werden sollte?

Antwort

2

Leider ist dies eine ziemlich lange Antwort. Ich benutzte auch AutoGenerateProperties="True", aber ich hatte ein ähnliches Problem.

Meine resultierende Lösung wurde die PropertyDefinition zu füllen, wie Sie vorgeschlagen. Ich tat dies programmatisch, da ich am Ende einige ziemlich spezielle Fälle hatte, in denen ich wollte, dass Eigenschaften dynamisch auf der Grundlage des Inhalts einer Sammlung erstellt wurden. Eine Sache, die ich habe bemerkt, war, dass selbst durch programmatisch Überprüfung durch meine Klassen zu emulieren die AutoGenerateProperties="True" Feature Mine war viel schneller als ihre Lösung.

Um mit der Sichtbarkeit wie gewünscht zu arbeiten, musste ich meine eigene Attribute erstellen, um Elemente aus der PropertyGrid unsichtbar zu machen.

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

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

jedes Element, das in meinem Projekt ausgewählt werden kann, ist es ist eine eigene Implementierung eines PropertySetBase Klasse, die so wie Eigenschaftsdefinitionen hat:

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

und die Logik, um dann in der currentPropertySelection die PropertySetBase s zu verarbeiten Sammlung.

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; 
    } 
} 

Als es tatsächlich zu zeigen,/die Eigenschaften verbergen ich folgendes getan: entsprechend

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; 
} 

dann innerhalb der PreparePropertyItem Ereignishandler ich für meine VisibilityAttribute überprüfen und die Eigenschaft Artikel aktualisieren.

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; 
      } 
     } 
    } 
}