Property Value Editoren für Silverlight-Steuerelemente
Einführung
Dies ist Teil der Reihe über gestalterische Umsetzung Zeit Änderungen in Silverlight Toolkit März 2009 Veröffentlichung . Dieser Beitrag beschreibt, wie das Bearbeiten von Eigenschaften Erlebnis für Silverlight-Steuerelemente mithilfe Eigenschaftswert Editor und Typkonverter zu verbessern. Ich werde mit der Beschreibung der gesamten Architektur Bearbeiten von Eigenschaften in WPF / Silverlight-Designer-Erweiterbarkeit Rahmen beginnen, dann verwenden Sie Beispiele in Silverlight Toolkit März 2009 Veröffentlichung zu demonstrieren, wie es gemacht wird, und einzigartige Themen / Tricks in Silverlight Entwurfszeit Entwicklung.
Eigenschaftenbearbeitungsarchitektur
Optisch Bearbeitung von Objekteigenschaften ist ein wichtiger Teil von Designern. Designer in der Regel nicht wissen, wie man Eigenschaften von benutzerdefinierten Typ (struct, Klasse oder Schnittstelle), viel weniger leisten, um einen schönen Schnitt Benutzeroberfläche bieten. Control-Entwickler müssen in der Regel bieten TypeConverter , PropertyValueEditor , oder beides, um Anzeige / Bearbeitungs-und UI-XAML-Serialisierung für benutzerdefinierte Eigenschaften der Arten liefern.
Der Designer erweiterbares Framework definiert drei Arten von Eigenschaftswert Editor: Inline-Editor, erweiterter Editor, und Dialog-Editor, die jeweils von einer Klasse implementiert:
Bearbeiten von UI dieser Editoren sind definiert durch DataTemplate . Das Anwesen der bearbeitet wird, um als Redakteur ausgesetzt DataContext von PropertyValue Typ. UI-Editor in der Regel auf die zugrunde liegende Eigenschaft, die über eine der drei Eigenschaften bearbeitet binden PropertyValue : Wert , StringValue , oder Sammlung .
PropertyValueEditor
PropertyValueEditor hält einen einzigen Inline-Editor definiert durch InlineEditorTemplate Eigentum. Inline-Editor erscheint in der Eigenschaften-Fenster. Unten sehen Sie ein einfaches Beispiel für InlineEditorTemplate das eine TextBox verwendet zum Anzeigen und Bearbeiten einer Eigenschaft:
x:Key ="TextBoxEditor" > <DataTemplate x: Key = "TextBoxEditor"> Text ="{Binding Path=Value}" /> <TextBox Text = "{Binding Path = Wert}" /> > </ DataTemplate>
ExtendedPropertyValueEditor
x:Key ="inlineEditor" > < Button Content ="..." Command ="{x:Static <DataTemplate x: Key = "inlineEditor"> <-Taste Content = "..." Command = "{x: Static > Path = Wert} "/> </ DataTemplate>
DialogPropertyValueEditor
DialogPropertyValueEditor hat zwei Redakteuren zu: Der Inline-Editor aus geerbt PropertyValueEditor , und eine zusätzliche Dialog-Editor definiert durch DialogEditorTemplate Eigentum. Der Dialog-Editor ist in der Regel durch Inline-Editor über knallte PropertyValueEditorCommands . ShowDialogEditor Befehl. Unten ist ein einfaches Beispiel:
x:Key ="inlineEditor" > < Button Content ="..." Command ="{x:Static <DataTemplate x: Key = "inlineEditor"> <-Taste Content = "..." Command = "{x: Static ="Center" HorizontalAlignment ="Right" Margin ="0,0,4,4" /> < TextBox Text ="{Binding Name: "VerticalAlignment =" center "HorizontalAlignment =" right "Margin =" 0,0,4,4 "/> <TextBox Text =" {Binding
Implementieren Sie benutzerdefinierte Eigenschaften-Editor
Um eine benutzerdefinierte Eigenschaften-Editor für ein Silverlight-Steuerelement zu implementieren:
- implementieren eine benutzerdefinierte Eigenschaft Editor-Klasse
- erben von PropertyValueEditor, ExtendedPropertyValueEditor oder DialogPropertyValueEditor
- setzen Sie den Editor-Vorlage (n): InlineEditorTemplate , ExtendedEditorTemplate , und / oder DialogEditorTemplate ;
- Ordnen Sie den Editor für benutzerdefinierte Eigenschaften mit einer Eigenschaft eines Silverlight-Steuerelement über eine AddCustomAttributes Ruf, so etwas wie
- Eine korrekt implementierte Eigenschaft Wert Editor muss folgende Anforderungen erfüllen:
- Der Wert der Eigenschaft Editor ist so zu gestalten, dass die Inline-Editor und erweiterter Editor Teile unabhängig voneinander verwendet werden können.
- Eine Eigenschaft, Wert-Editor darf nicht speichern Zustand. Eigenschaft Wert-Editoren sind staatenlos, kann zwischengespeichert werden durch einen Host-Implementierung und können über mehrere Eigenschaftswerte wieder verwendet werden.
- Eine Eigenschaft, Wert-Editor darf nicht davon ausgehen, dass nur ein Wert Editor Teil (view / Inline / extended)-Steuerung aktiv ist, zu einem bestimmten Zeitpunkt. Zum Beispiel könnte ein Dialogfeld haben den Blick Teilnummer, Inline-Teil, und erweiterte UI-Teil aktiv zur gleichen Zeit.
- Eine Kontrolle im Rahmen einer Eigenschaftswert Editor implementiert darf nicht speichern Zustand. Eine Kontrolle als Teil einer Wert-Editor implementiert sollten nicht davon ausgehen, dass diese nur auf eine Eigenschaft Wert gebunden zu sein. Kontrollen können recycelt, verschiedene Eigenschaftswerte ändern. Jede Information, die zwischengespeichert wird sollte gespült, wenn das Datenmodell aktualisiert wird.
- Eine Kontrolle im Rahmen einer Eigenschaftswert Editor implementiert sein müssen keine Annahmen über den Host oder übergeordneten Steuerelemente. Die einzigen Kommunikations-Mechanismen, die verwendet werden sollten, sind die PropertyValue Datenmodell, über die DataContext , und die Standard-Satz von Befehlen.
- Sie können mehr über das Bearbeiten von Eigenschaften Architektur und Designer-Erweiterbarkeit Rahmen auf MSDN.
Beziehen sich sowohl auf WPF und Silverlight Assemblies
Ein Design Assembly ist eine .NET / WPF-Assembly von Visual Studio oder Blend-geladen, aber es muss in der Regel Silverlight-Assemblys (zumindest das Silverlight-Steuerelement Montage bietet es Funktionen für die Design-Zeit) zu verweisen. Dies kann zu Mehrdeutigkeiten Referenz für Design-Montage-Projekt: es manchmal braucht, um die gleiche vollqualifizierte Typ in WPF und Silverlight, sagen System.Windows.FrameworkElement sowohl in PresentationFramework.dll von WPF und Silverlight von System.Windows.dll. Um Verwirrung zu vermeiden, Visual Studio, können Sie mit extern-Alias zu WPF und Silverlight Referenzen zu unterscheiden.
Zum Beispiel, siehe Screenshot unten für Controls.DataVisualization.Toolkit.Design Projekt in Silverlight 3 Toolkit im März 2009 Veröffentlichung :
- das Projekt auf beide PresentationFramework und System.Windows, aber System.Windows ist unter Silverlight alias, anstelle der standardmäßigen globalen Pseudonyms gestattet. . Die Referenz unter Silverlight System.Windows Alias wird in CSPROJ-Datei wie unten fort:
Include ="System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL" > <Hinweis enthalten = "System.Windows, Version = 2.0.5.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e, processorArchitecture = MSIL"> > False </ SpecificVersion > <SpecificVersion> false </ SpecificVersion> > ..\Binaries\System.Windows.dll </ HintPath > <HintPath> .. \ Binaries \ System.Windows.dll </ HintPath> > False </ Private > <Private> false </ Private> > Silverlight </ Aliases > <Aliases> Silverlight </ Aliases> > </ Reference>
- im Source-Code, fügen wir
extern alias Silverlight; mit SSW = :: Silverlight System.Windows;
Referenz-und Silverlight-FrameworkElement über SSW :: FrameworkElement.
TextBoxEditor
Es gibt einen Inline-Editor TextBoxEditor in Controls.DataVisualization.Toolkit.Design Projekt zum Anzeigen und Bearbeiten Titel Eigentum der Objekttyp für [Area | Bar | Bubble | Spalte | Line | Torte | Scatter] Serie und Chart-Steuerelemente, wie unten dargestellt:
Text im Feld Titel im Eigenschaften-Fenster auf der rechten Seite gefüllt zeigt sich automatisch in XAML und Design-Ansichten in der Mitte.
Die Umsetzung der TextBoxEditor folgte die beschriebenen Schritte vor:
- TextBoxEditor ist eine Unterklasse von PropertyValueEditor. Es setzt InlineEditorTemplate in seiner Default-Konstruktor. Hier benutze ich anstelle von XAML-Code, um das Konstrukt DataTemplate , denn irgendwie habe ich nicht bekommen kann XAML zu bauen, und alles in XAML kann in C # umgeschrieben werden sowieso.
- Es ist mit Chart.Title in ChartMetadata.cs (siehe assoziiert Design Time Feature-Implementierung in Silverlight-Toolkit für weitere Informationen zu * Metadata.cs-Dateien)
TextBoxEditor.cs:
/ / (C) Copyright Microsoft Corporation. / / Diese Quelle unter der Microsoft Public License (Ms-PL) ist. / / Bitte beachten Sie http://go.microsoft.com/fwlink/?LinkID=131993 für weitere Einzelheiten. / / Alle sonstigen Rechte TextBoxEditor : PropertyValueEditor { /// <summary> /// Preserve the constructor prototype from PropertyValueEditor. /// </summary> /// <param name="inlineEditorTemplate">Inline editor template.</param> public TextBoxEditor(DataTemplate inlineEditorTemplate) : base (inlineEditorTemplate) { } /// <summary> /// Default constructor builds the default TextBox inline editor template. /// </summary> public TextBoxEditor() { FrameworkElementFactory textBox = new FrameworkElementFactory( typeof (TextBox)); Binding binding = new Binding(); binding.Path = new PropertyPath( "Value" ); binding.Mode = BindingMode.TwoWay; textBox.SetBinding(TextBox.TextProperty, binding); DataTemplate dt = new DataTemplate(); dt.VisualTree = textBox; InlineEditorTemplate = dt; } } } . {/ / / <summary> / / / Einfache TextBox Inline-Editor / / / </ summary> public partial class TextBoxEditor:. PropertyValueEditor {/ / / <summary> / / / Erhalten Sie den Konstruktorprototyp aus PropertyValueEditor / / / </ summary> / / / <param name="inlineEditorTemplate"> Inline-Editor Vorlage </ param> public TextBoxEditor (DataTemplate inlineEditorTemplate):. Basis (inlineEditorTemplate) {} / / / <summary> / / / Standardkonstruktor baut das Standard-TextBox-Inline- Editor Template / / / </ summary> public TextBoxEditor () {FrameworkElementFactory textBox = new FrameworkElementFactory (typeof (TextBox));. Binding binding = new Binding (); binding.Path = new PropertyPath ("Value"); binding.Mode = BindingMode.TwoWay; textBox.SetBinding (TextBox.TextProperty, Bindung); DataTemplate dt = new DataTemplate (); dt.VisualTree = TextBox; InlineEditorTemplate = dt;}}}
CultureInfoEditor
Mein Kollege RJ schrieb Inline-Editor für CultureInfoEditor TimePicker.Culture Eigentum, da die Standard-Bearbeitung Erlebnis für CultureInfo in Blend führt auf das ungültige XAML. Unten Screenshot zeigt die CultureInfoEditor verwendet eine ComboBox, um alle CultureInfo anzuzeigen und erzeugt Recht XAML.
CultureInfoEditor ist ein komplexeres Beispiel als TextBoxEditor, wirklich zeigt, wie die zugrunde liegenden Immobilie mit Editor über DataContext-Eigenschaft assoziiert ist.
CultureInfoEditor.cs:
/ / (C) Copyright Microsoft Corporation. / / Diese Quelle unter der Microsoft Public License (Ms-PL) ist. / / Bitte beachten Sie http://go.microsoft.com/fwlink/?LinkID=131993 für weitere Einzelheiten. / / Alle sonstigen Rechte CultureInfoEditor : PropertyValueEditor { /// <summary> /// The ComboBox being used to edit the value. /// </summary> private ComboBox _owner; /// <summary> /// Preserve the constructor prototype from PropertyValueEditor. /// </summary> /// <param name="inlineEditorTemplate">Inline editor template.</param> public CultureInfoEditor(DataTemplate inlineEditorTemplate) : base (inlineEditorTemplate) { } /// <summary> /// Default constructor builds a ComboBox inline editor template. /// </summary> public CultureInfoEditor() { // not using databinding here because Silverlight does not support // the WPF CultureConverter that is used by Blend. FrameworkElementFactory comboBox = new FrameworkElementFactory( typeof (ComboBox)); comboBox.AddHandler( ComboBox.LoadedEvent, new RoutedEventHandler( (sender, e) => { _owner = (ComboBox) sender; _owner.SelectionChanged += EditorSelectionChanged; INotifyPropertyChanged data = _owner.DataContext as INotifyPropertyChanged; if (data != null ) { data.PropertyChanged += DatacontextPropertyChanged; } _owner.DataContextChanged += CultureDatacontextChanged; })); comboBox.SetValue(ComboBox.IsEditableProperty, false ); comboBox.SetValue(ComboBox.DisplayMemberPathProperty, "DisplayName" ); comboBox.SetValue(ComboBox.ItemsSourceProperty, CultureInfo.GetCultures(CultureTypes.SpecificCultures)); DataTemplate dt = new DataTemplate(); dt.VisualTree = comboBox; InlineEditorTemplate = dt; } /// <summary> /// Handles the SelectionChanged event of the owner control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> /// instance containing the event data.</param> private void EditorSelectionChanged( object sender, SelectionChangedEventArgs e) { // serialize with name. object DataContext = _owner.DataContext; DataContext .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .SetValue(DataContext, ((CultureInfo)_owner.SelectedItem).Name, new object [] { }); } /// <summary> /// Handles the PropertyChanged event of the context object. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param> private void DatacontextPropertyChanged( object sender, PropertyChangedEventArgs e) { // deserialize from name. if (e.PropertyName == "Value" ) { object value = sender .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .GetValue(sender, new object [] { }); if ( value != null ) { if ( value is string ) { CultureInfo setCulture = new CultureInfo( value .ToString()); _owner.SelectedItem = setCulture; } } } } /// <summary> /// Called when the context is changed. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> private void CultureDatacontextChanged( object sender, DependencyPropertyChangedEventArgs e) { INotifyPropertyChanged old = e.OldValue as INotifyPropertyChanged; if (old != null ) { old.PropertyChanged -= DatacontextPropertyChanged; } INotifyPropertyChanged newDataContext = e.NewValue as INotifyPropertyChanged; if (newDataContext != null ) { newDataContext.PropertyChanged += DatacontextPropertyChanged; } } } } .. {/ / / <summary> / / / Editor für CultureInfo / / / </ summary> / / / <remarks> unterstützt derzeit noch nicht verbindlich von XAML an die Redaktion </ remarks> public class CultureInfoEditor: PropertyValueEditor {/ / / <summary> / / / Der ComboBox genutzt, um den Wert zu bearbeiten / / / </ summary> private ComboBox _owner;.. / / / <summary> / / / Erhalten Sie den Konstruktorprototyp aus PropertyValueEditor / / / </ summary> / / / <param name="inlineEditorTemplate"> Inline-Editor Vorlage </ param> public CultureInfoEditor (DataTemplate inlineEditorTemplate):. Basis (inlineEditorTemplate) {} / / / <summary> / / / Standardkonstruktor erstellt eine ComboBox Inline-Editor Vorlage. / / / </ summary> public CultureInfoEditor () {/ / nicht benutzen, weil hier DataBinding Silverlight nicht unterstützt, / / die WPF CultureConverter, die durch Mischung verwendet wird FrameworkElementFactory comboBox = new FrameworkElementFactory (typeof (ComboBox));. comboBox.AddHandler ( ComboBox.LoadedEvent, neue RoutedEventHandler ((sender, e) => {_owner = (ComboBox) sender; _owner.SelectionChanged + = EditorSelectionChanged; INotifyPropertyChanged data = _owner.DataContext als INotifyPropertyChanged; if (data = null) {data.PropertyChanged + = DatacontextPropertyChanged;} _owner.DataContextChanged + = CultureDatacontextChanged;})); comboBox.SetValue (ComboBox.IsEditableProperty, false); comboBox.SetValue (ComboBox.DisplayMemberPathProperty, "DisplayName"); comboBox.SetValue (ComboBox.ItemsSourceProperty, CultureInfo.GetCultures (CultureTypes.SpecificCultures)); DataTemplate dt = new DataTemplate (); dt.VisualTree = comboBox; InlineEditorTemplate = dt;.} / / / <summary> / / / Behandelt das SelectionChanged-Ereignis des Eigentümers Steuerung / / / </ summary > / / / <param name="sender"> Die Quelle des Ereignisses. </ param> / / / <param name="e"> Die <siehe cref="System.Windows.Controls.SelectionChangedEventArgs"/> / / / Instanz mit den Event-Daten </ param> private void EditorSelectionChanged (object sender, SelectionChangedEventArgs e) {/ / mit Namen serialisieren Objekt DataContext = _owner.DataContext;.... DataContext GetType () GetProperty ("Value", BindingFlags. .. Public | BindingFlags.Instance | BindingFlags.GetProperty) SetValue (DataContext, ((CultureInfo) _owner.SelectedItem) Name, new object [] {});} / / / <summary> / / / Verarbeitet das PropertyChanged-Ereignis von der Kontext-Objekt. / / / </ summary> / / / <param name="sender"> der Quelle des Ereignisses. </ param> / / / <param name="e"> Die <siehe cref = "System. ComponentModel.PropertyChangedEventArgs "/>-Instanz mit den Ereignisdaten. </ param> private void DatacontextPropertyChanged (object sender, PropertyChangedEventArgs e) {/ / Name aus deserialisieren. if (e.PropertyName ==" Value ") {Objektwert = Absender. .. GetType () GetProperty ("Value", BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) GetValue (Absender, new object [] {}); if (value = null) {if (Wert ist string) { CultureInfo setCulture = new CultureInfo (Wert ToString ().); _owner.SelectedItem = setCulture;.}}}} / / / <summary> / / / Wird aufgerufen, wenn der Kontext verändert wird / / / </ summary> / / / < param name = "Absender"> Der Absender. </ param> / / / <param name="e"> Die <siehe cref="System.Windows.DependencyPropertyChangedEventArgs"/> Instanz mit den Ereignisdaten. </ param> private Erlöschen CultureDatacontextChanged (object sender, DependencyPropertyChangedEventArgs e) {INotifyPropertyChanged alt = e.OldValue als INotifyPropertyChanged; if (alt = null) {old.PropertyChanged - = DatacontextPropertyChanged;} INotifyPropertyChanged newDataContext = e.NewValue als INotifyPropertyChanged; if (newDataContext = null ) {newDataContext.PropertyChanged + = DatacontextPropertyChanged;}}}}
ExpandableObjectConverter
Wie eingangs diskutiert, neben benutzerdefinierte Eigenschaft Wert-Editoren, manchmal kann man mit geeigneten Typkonverter, um gute Bearbeitung Erfahrung und XAML-Serialisierung bieten. Ein Beispiel dafür ist ColumnSeries.DependentRangeAxis: es ist der Typ IRangeAxis, Blend nicht weiß, wie um ihn zu bearbeiten, so zeigt es DependentRangeAxis als nur lesen in Properties Panel. Durch die Zuordnung ExpandableObjectConverter zu ColumnSeries.DependentRangeAxis:
b.AddCustomAttributes ( Extensions.GetMemberName <ColumnSeries> (x => x.DependentRangeAxis), (ExpandableObjectConverter))); neue TypeConverterAttribute (typeof (ExpandableObjectConverter))); b.AddCustomAttributes ( Extensions.GetMemberName <ColumnSeries> (x => x.IndependentAxis), (ExpandableObjectConverter))); neue TypeConverterAttribute (typeof (ExpandableObjectConverter)));
Mischung zeigt eine neue Schaltfläche neben dieser Eigenschaft im Eigenschaften-Panel, wenn darauf geklickt wird, öffnet es die Objektauswahl-Dialog, mit der Unterkunft Art IRangeAxis gefiltert:
Abschluss
Blend und Silverlight zusammen ermöglichen es Entwicklern, erstaunlich UI gegen echte Kontrollen direkt erstellen, so ist es sehr wichtig, dass die Kontrolle Entwickler Designer Erfahrung nehmen als Teil der globalen Steuerung Gestaltung und Umsetzung. Mit einer benutzerdefinierten Eigenschaft Editor, der schöne Bearbeitung UI bietet und erzeugt richtige XAML ist ein wichtiger Bestandteil des Designers Erfahrung. Hoffentlich Dieser Beitrag hilft Ihnen zu verstehen, wie Sie benutzerdefinierte Eigenschaft Editoren erstellen. Vielen Dank!








Recent Comments