Anpassen des Eigenschaftenfensters

Sie können das Aussehen und Verhalten des Eigenschaftsfensters in Ihrer domänenspezifischen Sprache (Domain-Specific Language, DSL) in Visual Studio anpassen. In Ihrer DSL-Definition definieren Sie Domäneneigenschaften für jede Domänenklasse. Wenn Sie in einem Diagramm oder im Modell-Explorer eine Instanz der Klasse auswählen, werden standardmäßig alle Domäneneigenschaften im Eigenschaftenfenster aufgelistet. Auf diese Weise können Sie die Werte von Domäneneigenschaften auch dann sehen und bearbeiten, wenn sie keinem Formfelde im Diagramm zugeordnet sind.

Namen, Beschreibungen und Kategorien

Name und Anzeigename: In Ihrer Definition einer Domäneneigenschaft ist der Anzeigename der Eigenschaft der Name, der zur Laufzeit im Eigenschaftsfenster angezeigt wird. Im Gegensatz dazu wird der Name verwendet, wenn Sie Programmcode zur Aktualisierung der Eigenschaft schreiben. Der Name muss ein korrekter alphanumerischer CLR-Name sein, der Anzeigename hingegen kann Leerzeichen enthalten.

Wenn Sie den Namen einer Eigenschaft in der DSL-Definition festlegen, wird ihr Anzeigename automatisch auf eine Kopie des Namens festgelegt. Wenn Sie z. B. einen Namen in Pascal-Schreibweise wie etwa „FuelGauge“ eingeben, enthält der Anzeigename automatisch ein Leerzeichen: „Fuel Gauge“. Sie können den Anzeigenamen jedoch explizit auf einen anderen Wert festlegen.

Beschreibung. Die Beschreibung einer Domäneneigenschaft wird an zwei Stellen angezeigt:

  • Im unteren Bereich des Eigenschaftsfensters, wenn der Benutzer die Eigenschaft auswählt. Sie können dem Benutzer anhand der Beschreibung erklären, was die Eigenschaft repräsentiert.

  • Im generierten Programmcode. Wenn Sie die Dokumentationsfunktionen verwenden, um die API-Dokumentation zu extrahieren, wird sie als Beschreibung dieser Eigenschaft in der API angezeigt.

Kategorie Eine Kategorie ist eine Überschrift im Eigenschaftenfenster.

Verfügbarmachen von Stilfeatures

Einige der dynamischen Eigenschaften von grafischen Elementen können als Domäneneigenschaften dargestellt oder verfügbar gemacht werden. Ein auf diese Weise verfügbar gemachtes Feature kann vom Benutzer aktualisiert werden und lässt sich leichter über den Programmcode aktualisieren.

Klicken Sie mit der rechten Maustaste auf eine Formklasse in der DSL-Definition, zeigen Sie auf Bereitgestellte hinzufügen, und wählen Sie dann ein Feature aus.

Für Formen können Sie die Eigenschaften FillColor, OutlineColor, TextColor, OutlineDashStyle, OutlineThickness und FillGradientMode verfügbar machen. Für Connectors können Sie die Eigenschaften Color,TextColor, DashStyle und Thickness verfügbar machen. Für Diagrammen können die Eigenschaften FillColor und TextColor verfügbar gemacht werden.

Wenn die Benutzer Ihrer DSL ein Element in einem Modell auswählen, werden die Eigenschaften dieses Elements im Eigenschaftenfenster angezeigt. Sie können aber auch die Eigenschaften von bestimmten verwandten Elementen anzeigen. Dies ist nützlich, wenn Sie eine Gruppe von Elementen definiert haben, die zusammenarbeiten. Sie können beispielsweise ein Hauptelement und ein optionales Plug-In-Element definieren. Wenn das Hauptelement einer Form zugeordnet ist, das zweite Element jedoch nicht, kann es von Nutzen sein, alle Eigenschaften so zu sehen, als ob sie sich in einem einzigen Element befänden.

Dieser Effekt wird als Eigenschaftenweiterleitung bezeichnet und erfolgt in verschiedenen Fällen automatisch. In anderen Fällen können Sie die Eigenschaftenweiterleitung durch die Definition eines Domänentypdeskriptors erreichen.

Standardfälle für die Eigenschaftenweiterleitung

Wenn der Benutzer im Explorer eine Form, einen Connector oder ein Element auswählt, werden im Eigenschaftenfenster die folgenden Eigenschaften angezeigt:

  • Die in der Domänenklasse des Modellelements definierten Domäneneigenschaften, einschließlich derer, die in Basisklassen definiert sind. Eine Ausnahme bilden Domäneneigenschaften, für die Sie Is Browsable auf False festgelegt haben.

  • Die Namen von Elementen, die über Beziehungen mit der Multiplizität 0..1 verknüpft sind. Dies ist eine praktische Methode zur Anzeige optional verknüpfter Elemente, auch wenn Sie keine Connectorzuordnung für die Beziehung definiert haben.

  • Domäneneigenschaften der Einbettungsbeziehung, die auf das Element abzielt. Da Einbettungsbeziehungen in der Regel nicht explizit angezeigt werden, kann der Benutzer so ihre Eigenschaften sehen.

  • Domäneneigenschaften, die für die ausgewählte Form oder den ausgewählten Connector definiert sind.

Hinzufügen der Eigenschaftenweiterleitung

Um eine Eigenschaft weiterzuleiten, definieren Sie einen Domänentypdeskriptor. Wenn eine Domänenbeziehung zwischen zwei Domänenklassen besteht, können Sie einen Domänentypdeskriptor verwenden, um eine Domäneneigenschaft in der ersten Klasse auf den Wert einer Domäneneigenschaft in der zweiten Domänenklasse festzulegen. Wenn beispielsweise eine Beziehung zwischen einer Domänenklasse Book und einer Domänenklasse Author vorliegt, können Sie mit einem Domänentypdeskriptor dafür sorgen, dass beim Auswählen eines Buchs die Eigenschaft Name des Buchautors (Author) im Eigenschaftenfenster angezeigt wird.

Hinweis

Die Weiterleitung von Eigenschaften wirkt sich nur auf das Eigenschaftenfenster aus, wenn der Benutzer ein Modell bearbeitet. Sie definiert keine Domäneneigenschaft für die empfangende Klasse. Wenn Sie in anderen Teilen der DSL-Definition oder im Programmcode auf die weitergeleitete Domäneneigenschaft zugreifen möchten, müssen Sie auf das Weiterleitungselement zugreifen.

Im folgenden Verfahren wird davon ausgegangen, dass Sie eine DSL erstellt haben. In den ersten Schritten werden die Voraussetzungen zusammengefasst.

Weiterleiten einer Eigenschaft von einem anderen Element

  1. Erstellen Sie eine DSL-Tools-Lösung, die mindestens zwei Klassen enthält. In diesem Beispiel tragen die Klassen die Namen Book und Author. Zwischen Book und Author sollte eine Beziehung beliebiger Art bestehen.

    Die Multiplizität der Quellrolle (die Rolle aufseiten von Book) sollte 0..1 oder 1..1 lauten, sodass jedes Book über einen Author verfügt.

  2. Klicken Sie im DSL-Explorer mit der rechten Maustaste auf die Domänenklasse Book, und klicken Sie dann auf Neuen DomainTypeDescriptor hinzufügen.

    Unter dem Knoten Benutzerdefinierter Typdeskriptor wird ein Knoten namens Pfade benutzerdefinierter Eigenschaftendeskriptoren angezeigt.

  3. Klicken Sie mit der rechten Maustaste auf den Knoten Benutzerdefinierter Typdeskriptor und dann auf Neuen PropertyPath hinzufügen.

    Daraufhin wird unter dem Knoten Pfade von benutzerdefinierter Eigenschaftendeskriptoren ein neuer Eigenschaftenpfad angezeigt.

  4. Wählen Sie den neuen Eigenschaftenpfad aus, und legen Sie im Fenster Eigenschaften den Wert für Pfad zu Eigenschaft auf den Pfad des geeigneten Modellelements fest.

    Sie können den Pfad in einer Strukturansicht bearbeiten, indem Sie auf den nach unten weisenden Pfeil rechts neben dieser Eigenschaft klicken. Weitere Informationen zu Domänenpfaden finden Sie unter Domänenpfadsyntax. Nach der Bearbeitung sollte der Pfad etwa so aussehen wie BookReferencesAuthor.Author/!Author.

  5. Legen Sie Eigenschaft auf die Domäneneigenschaft Name von Author fest.

  6. Legen Sie Anzeigename auf Author Name fest.

  7. Transformieren Sie alle Vorlagen, erstellen Sie die DSL, und führen Sie sie aus.

  8. Erstellen Sie in einem Modelldiagramm ein Buch und einen Autor, und verknüpfen Sie diese über die Referenzbeziehung. Wählen Sie das Buchelement aus. Im Eigenschaftenfenster sollte nun zusätzlich zu den Eigenschaften des Buchs auch der Name des Autors angezeigt werden. Ändern Sie den Namen des verknüpften Autors, oder verknüpfen Sie das Buch mit einem anderen Autor, und beachten Sie, dass sich der Autorenname des Buches ändert.

Benutzerdefinierte Eigenschaften-Editoren

Das Eigenschaftenfenster bietet für den Typ jeder Domäneneigenschaft eine passende Standardbearbeitungsoberfläche. Für einen Aufzählungstyp wird dem Benutzer zum Beispiel eine Dropdownliste angezeigt, und für eine numerische Eigenschaft kann der Benutzer Ziffern eingeben. Dies gilt allerdings nur für die integrierten Typen. Wenn Sie einen externen Typ angeben, kann der Benutzer die Werte der Eigenschaft anzeigen, aber nicht bearbeiten.

Sie können jedoch die folgenden Editoren und Typen angeben:

  1. Einen weiteren Editor, der mit einem Standardtyp verwendet wird. Sie können zum Beispiel einen Dateipfad-Editor für eine Zeichenfolgeneigenschaft angeben.

  2. Einen externen Typ für die Domäneneigenschaft und einen entsprechenden Editor.

  3. Einen .NET-Editor wie z. B. den Dateipfad-Editor. Alternativ können Sie auch einen eigenen Eigenschaften-Editor erstellen.

    Eine Konvertierung von einem externen Typ in einen Typ (z. B. eine Zeichenfolge), für den ein Standard-Editor vorhanden ist.

    In einer DSL ist ein externer Typ jeder Typ, bei dem es sich nicht um einen der einfachen Typen (z. B. boolescher Typ oder Int32) oder um eine Zeichenfolge handelt.

Definieren einer Domäneneigenschaft mit einem externen Typ

  1. Fügen Sie im Projektmappen-Explorer im Projekt Dsl einen Verweis auf die Assembly (DLL) hinzu, die den externen Typ enthält.

    Bei der Assembly kann es sich um eine .NET-Assembly oder um eine von Ihnen bereitgestellte Assembly handeln.

  2. Fügen Sie den Typ zur Liste Domänentypen hinzu, sofern Sie dies nicht bereits getan haben.

    1. Öffnen Sie „DslDefinition.dsl“, und klicken Sie im DSL-Explorer mit der rechten Maustaste auf den Stammknoten. Klicken Sie dann auf Neuen externen Typ hinzufügen.

      Unter dem Knoten Domänentypen wird ein neuer Eintrag angezeigt.

      Warnung

      Der Menüpunkt befindet sich im DSL-Stammknoten, nicht im Knoten Domänentypen.

    2. Legen Sie den Namen und den Namespace des neuen Typs im Eigenschaftenfenster fest.

  3. Fügen Sie einer Domänenklasse auf die übliche Weise eine Domäneneigenschaft hinzu.

    Wählen Sie im Eigenschaftenfenster den externen Typ aus der Dropdownliste im Feld Typ aus.

    In dieser Phase können Benutzer die Werte der Eigenschaft anzeigen, aber nicht bearbeiten. Die angezeigten Werte werden von der ToString()-Funktion abgerufen. Sie könnten Programmcode zum Festlegen des Eigenschaftenwerts schreiben, zum Beispiel in einem Befehl oder einer Regel.

Festlegen eines Eigenschaften-Editors

Fügen Sie der Domäneneigenschaft ein CLR-Attribut in der folgenden Form hinzu:

[System.ComponentModel.Editor (
   typeof(AnEditor),
   typeof(System.Drawing.Design.UITypeEditor))]

Sie können das Attribut für eine Eigenschaft über den Eintrag Benutzerdefiniertes Attribut im Eigenschaftenfenster festlegen.

Der Typ von AnEditor muss von dem im zweiten Parameter angegebenen Typ abgeleitet sein. Der zweite Parameter sollte entweder UITypeEditor oder ComponentEditor lauten. Weitere Informationen finden Sie unter EditorAttribute.

Sie können einen eigenen Editor oder einen .NET-Editor angeben, z. B. FileNameEditor oder ImageEditor. Verwenden Sie beispielsweise das folgende Verfahren, um über eine Eigenschaft zu verfügen, in die der Benutzer einen Dateinamen eingeben kann.

Definieren einer Domäneneigenschaft für den Dateinamen

  1. Fügen Sie in Ihrer DSL-Definition eine Domäneneigenschaft zu einer Domänenklasse hinzu.

  2. Wählen Sie die neue Eigenschaft aus. Geben Sie im Eigenschaftenfenster im Feld Benutzerdefiniertes Attribut das folgende Attribut ein. Klicken Sie zur Eingabe dieses Attributs auf die Auslassungspunkte [...], und geben Sie dann den Attributnamen und die Parameter separat ein:

    [System.ComponentModel.Editor (
       typeof(System.Windows.Forms.Design.FileNameEditor)
       , typeof(System.Drawing.Design.UITypeEditor))]
    
    
  3. Behalten Sie für den Typ der Domäneneigenschaft die Standardeinstellung String bei.

  4. Zum Testen des Editors vergewissern Sie sich, dass Benutzer den Dateinamen-Editor öffnen können, um Ihre Domäneneigenschaften zu bearbeiten.

    1. Drücken Sie STRG+F5 oder F5. Öffnen Sie in der Debuglösung eine Testdatei. Erstellen Sie ein Element der Domänenklasse, und wählen Sie es aus.

    2. Wählen Sie im Eigenschaftenfenster die Domäneneigenschaft aus. Im Feld für den Wert werden Auslassungspunkte [...] angezeigt.

    3. Klicken Sie auf die Auslassungspunkte. Es wird ein Dateidialogfeld geöffnet. Wählen Sie eine Datei aus, und schließen Sie das Dialogfeld. Der Dateipfad entspricht nun dem Wert der Domäneneigenschaft.

Definieren eines eigenen Eigenschaften-Editors

Sie können einen eigenen Editor definieren. Auf diese Weise können Sie dem Benutzer entweder erlauben, einen von Ihnen definierten Typ zu ändern oder einen Standardtyp auf spezielle Weise zu bearbeiten. Sie könnten dem Benutzer zum Beispiel erlauben, eine Zeichenfolge einzugeben, die eine Formel darstellt.

Sie definieren einen Editor, indem Sie eine von UITypeEditor abgeleitete Klasse schreiben. Ihre Klasse muss folgende Methoden überschreiben:

  • EditValue, um mit dem Benutzer zu interagieren und den Eigenschaftenwert zu aktualisieren.

  • GetEditStyle, um anzugeben, ob Ihr Editor ein Dialogfeld öffnen oder ein Dropdownmenü bereitstellen soll.

Sie können zudem eine grafische Darstellung des Eigenschaftenwerts bereitstellen, die im Eigenschaftenraster angezeigt wird. Hierzu überschreiben Sie GetPaintValueSupported und PaintValue. Weitere Informationen finden Sie unter UITypeEditor.

Hinweis

Fügen Sie den Code in eine separate Codedatei im Projekt Dsl ein.

Zum Beispiel:

internal class TextFileNameEditor : System.Windows.Forms.Design.FileNameEditor
{
  protected override void InitializeDialog(System.Windows.Forms.OpenFileDialog openFileDialog)
  {
    base.InitializeDialog(openFileDialog);
    openFileDialog.Filter = "Text files(*.txt)|*.txt|All files (*.*)|*.*";
    openFileDialog.Title = "Select a text file";
  }
}

Legen Sie zur Verwendung dieses Editors das Benutzerdefinierte Attribut einer Domäneneigenschaft wie folgt fest:

[System.ComponentModel.Editor (
   typeof(MyNamespace.TextFileNameEditor)
   , typeof(System.Drawing.Design.UITypeEditor))]

Weitere Informationen finden Sie unter UITypeEditor.

Angeben einer Dropdownliste mit Werten

Sie können eine Liste mit Werten angeben, aus der ein Benutzer auswählen kann.

Hinweis

Dieses Verfahren liefert eine Liste mit Werten, die sich zur Laufzeit ändern können. Wenn Sie eine Liste bereitstellen möchten, die sich nicht ändert, sollten Sie stattdessen einen Aufzählungstyp als Typ für Ihre Domäneneigenschaft verwenden.

Zum Definieren einer Liste mit Standardwerten fügen Sie Ihrer Domäneneigenschaft ein CLR-Attribut der folgenden Form hinzu:

[System.ComponentModel.TypeConverter
(typeof(MyTypeConverter))]

Definieren Sie eine Klasse, die sich von TypeConverter ableitet. Fügen Sie den Code in eine separate Datei im Projekt Dsl ein. Beispiel:

/// <summary>
/// Type converter that provides a list of values
/// to be displayed in the property grid.
/// </summary>
/// <remarks>This type converter returns a list
/// of the names of all "ExampleElements" in the
/// current store.</remarks>
public class MyTypeConverter : System.ComponentModel.TypeConverter
{
  /// <summary>
  /// Return true to indicate that we return a list of values to choose from
  /// </summary>
  /// <param name="context"></param>
  public override bool GetStandardValuesSupported
    (System.ComponentModel.ITypeDescriptorContext context)
  {
    return true;
  }

  /// <summary>
  /// Returns true to indicate that the user has
  /// to select a value from the list
  /// </summary>
  /// <param name="context"></param>
  /// <returns>If we returned false, the user would
  /// be able to either select a value from
  /// the list or type in a value that is not in the list.</returns>
  public override bool GetStandardValuesExclusive
      (System.ComponentModel.ITypeDescriptorContext context)
  {
    return true;
  }

  /// <summary>
  /// Return a list of the values to display in the grid
  /// </summary>
  /// <param name="context"></param>
  /// <returns>A list of values the user can choose from</returns>
  public override StandardValuesCollection GetStandardValues
      (System.ComponentModel.ITypeDescriptorContext context)
  {
    // Try to get a store from the current context
    // "context.Instance"  returns the element(s) that
    // are currently selected i.e. whose values are being
    // shown in the property grid.
    // Note that the user could have selected multiple objects,
    // in which case context.Instance will be an array.
    Store store = GetStore(context.Instance);

    List<string> values = new List<string>();

    if (store != null)
    {
      values.AddRange(store.ElementDirectory
        .FindElements<ExampleElement>()
        .Select<ExampleElement, string>(e =>
      {
        return e.Name;
      }));
    }
    return new StandardValuesCollection(values);
  }

  /// <summary>
  /// Attempts to get to a store from the currently selected object(s)
  /// in the property grid.
  /// </summary>
  private Store GetStore(object gridSelection)
  {
    // We assume that "instance" will either be a single model element, or
    // an array of model elements (if multiple items are selected).

    ModelElement currentElement = null;

    object[] objects = gridSelection as object[];
    if (objects != null && objects.Length > 0)
    {
      currentElement = objects[0] as ModelElement;
    }
    else
    {
        currentElement = gridSelection as ModelElement;
    }

    return (currentElement == null) ? null : currentElement.Store;
  }

}