Ich untersuche den Silverlight-Verhaltensmechanismus, um das Model-View-ViewModel-Muster in meinen Silverlight-Anwendungen zu verwenden. Zunächst versuche ich, eine einfache Hello World zu erhalten, aber ich bin völlig in einem Fehler gefangen, für den ich keine Lösung finden kann.Fehler beim Binden einer Abhängigkeitseigenschaft an ein benutzerdefiniertes Verhalten
Was ich gerade habe ist eine Seite, die nur eine Schaltfläche enthält, die eine Nachricht anzeigen sollte, wenn Sie darauf klicken. Das click-Ereignis wird mithilfe einer von Behaviour abgeleiteten Klasse behandelt, und die Nachricht wird als eine Abhängigkeitseigenschaft des Verhaltens selbst angegeben. Das Problem tritt auf, wenn versucht wird, die Nachrichteneigenschaft an eine Eigenschaft in einer Viewmodel-Klasse zu binden, die als Datenkontext verwendet wird: Ich erhalte eine Ausnahme in dem Aufruf von InitializeComponent
in der Ansicht.
Hier ist der ganze Code, den ich benutze, wie Sie sehen können, ist es ziemlich einfach. Zunächst wird die Auszeichnung von der Hauptseite und die Ansicht enthält:
MyPage
<UserControl x:Class="MyExample.MyPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyExample"
>
<Grid x:Name="LayoutRoot">
<local:MyView/>
</Grid>
</UserControl>
MyView (der Textblock gibt es nur zu prüfen, ob die Bindungs Syntax korrekt ist)
<UserControl x:Class="MyExample.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:MyExample"
Width="400" Height="300">
<StackPanel Orientation="Vertical" x:Name="LayoutRoot" Background="White">
<StackPanel.Resources>
<local:MyViewmodel x:Key="MyResource"/>
</StackPanel.Resources>
<TextBlock Text="This button will display the following message:"/>
<TextBlock Text="{Binding MyMessage, Source={StaticResource MyResource}}" FontStyle="Italic"/>
<Button x:Name="MyButton" Content="Click me!">
<i:Interaction.Behaviors>
<local:MyBehavior Message="{Binding MyMessage, Source={StaticResource MyResource}}"/>
</i:Interaction.Behaviors>
</Button>
</StackPanel>
</UserControl>
Jetzt die Code, gibt es zwei Klassen: einen für das Verhalten und ein anderer für das Viewmodel:
MyViewmodel
public class MyViewmodel
{
public string MyMessage
{
get { return "Hello, world!"; }
}
}
MyBehavior
public class MyBehavior : Behavior<Button>
{
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message",
typeof(string), typeof(MyBehavior),
new PropertyMetadata("(no message)"));
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Click += new RoutedEventHandler(AssociatedObject_Click);
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Click -= new RoutedEventHandler(AssociatedObject_Click);
}
void AssociatedObject_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(Message);
}
}
Einfache genug, aber Dieser Code löst eine AG_E_PARSER_BAD_PROPERTY_VALUE [Line: 15 Position: 43]
(direkt am Anfang des Werts für die Eigenschaft Nachricht festgelegt) beim Ausführen aus. Ich bin mir sicher, dass mir etwas fehlt, aber was?
Weitere Informationen: Wenn ich die Bindung aus der Message-Eigenschaft auf MyBehavior entfernen (das heißt, wenn ich den Wert auf eine statische Zeichenfolge festlegen), funktioniert es einwandfrei. Außerdem ziele ich auf silverlight 3 RTW.
Vielen Dank!
UPDATE
Es scheint, dass im Gegensatz zu WPF, Silverlight unterstützt keine Daten auf ein beliebiges Objekt Bindung von DependencyObject abgeleitet, sondern nur auf Objekte aus Framework abzuleiten. Dies ist bei Verhalten nicht der Fall, daher funktioniert die Bindung nicht.
Ich habe eine Problemumgehung gefunden here, in Form von etwas namens Ersatzbinder. Grundsätzlich geben Sie das Element und die Eigenschaft, die verknüpft werden sollen, sowie den Wert als Attribute des FrameworkElement an, das das Nicht-FrameworkElement-Objekt enthält.
UPDATE 2
Das Surrogat Bindemittel funktioniert nicht, wenn die Framework ein Interaction.Behaviors Unterelement enthält.
Ich habe eine andere Lösung here gefunden, und diese scheint zu funktionieren. Diesmal ist der verwendete Trick ein DeepSetter. Sie definieren einen dieser Setter als statische Ressource für das enthaltende StackPanel und verweisen dann die Ressource aus dem Verhalten. Also in meinem Beispiel, sollten wir die Ressourcen Abschnitt Stackpanel erweitern wie folgt:
<StackPanel.Resources>
<local:MyViewmodel x:Key="MyResource"/>
<local:DeepSetter
x:Key="MyBehaviorSetter"
TargetProperty="Message"
BindingExport="{Binding MyMessage, Source={StaticResource MyResource}}"/>
</StackPanel.Resources>
... und ändern das Verhalten Erklärung Taste wie folgt:
<local:MyBehavior local:DeepSetter.BindingImport="{StaticResource MyBehaviorSetter}"/>
UPDATE 3
Gut Nachrichten: Datenbindung für jedes DependecyObject wird auf Silverlight 4 verfügbar sein: http://timheuer.com/blog/archive/2009/11/18/whats-new-in-silverlight-4-complete-guide-new-features.aspx#dobind
Ich benutze ein Verhalten mit einem benutzerdefinierten DP mit SL 4, ich habe keinen Fehler, aber die Bindung wird nicht verwendet, dh die Getter/Setter von Die Quelle wird nie aufgerufen. Hast du versucht ? – MatthieuGD
Ich bin bei SilverLight3 eingesperrt, also habe ich eine Erweiterungsmethode erstellt, die es mir ermöglicht, ein Verhalten aus einem Steuerelement zu extrahieren und die gewünschte Eigenschaft darauf festzulegen. Es ist hacky, aber könnte es sonst nicht funktionieren. – jtruelove