【发布时间】:2009-09-28 12:53:17
【问题描述】:
我正在探索 Silverlight 附加行为机制,以便在我的 Silverlight 应用程序中使用模型-视图-视图模型模式。首先,我试图让一个简单的 Hello World 工作,但我完全陷入了一个我无法找到解决方案的错误中。
我现在拥有的是一个仅包含一个按钮的页面,该按钮应在单击时显示一条消息。单击事件是通过使用从 Behavior 派生的类来处理的,并且消息被指定为行为本身的依赖属性。尝试将消息属性绑定到用作数据上下文的视图模型类上的属性时出现问题:我在视图中调用 InitializeComponent 时遇到异常。
这是我使用的所有代码,您可以看到它相当简单。首先是主页的标记和它包含的视图:
我的页面
<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(TextBlock 只是为了检查绑定语法是否正确)
<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>
现在的代码,有两个类:一个用于行为,另一个用于视图模型:
我的视图模型
public class MyViewmodel
{
public string MyMessage
{
get { return "Hello, world!"; }
}
}
我的行为
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);
}
}
足够简单,但是此代码在运行时会引发AG_E_PARSER_BAD_PROPERTY_VALUE [Line: 15 Position: 43](就在为 Message 属性设置的值的开头)异常。我确定我错过了什么,但是什么?
附加信息:如果我从 MyBehavior 上的 Message 属性中删除绑定(也就是说,如果我将其值设置为任何静态字符串),它可以正常工作。另外,我的目标是 silverlight 3 RTW。
非常感谢!
更新
似乎与 WPF 不同,Silverlight 不支持对派生自 DependencyObject 的任何对象进行数据绑定,而仅支持对派生自 FrameworkElement 的对象进行数据绑定。这不是 Behavior 的情况,因此绑定不起作用。
我找到了一种解决方法here,其形式为代理绑定器。基本上,您将要绑定的元素和属性以及值指定为包含非 FrameworkElement 对象的 FrameworkElement 的属性。
更新 2
当 FrameworkElement 包含 Interaction.Behaviors 子元素时,代理绑定器不起作用。
我找到了另一种解决方案here,这个似乎可行。这一次,使用的技巧是 DeepSetter。您将此类设置器之一定义为包含 StackPanel 上的静态资源,然后从行为中引用该资源。因此,在我的示例中,我们应该将 StackPanel 资源部分展开如下:
<StackPanel.Resources>
<local:MyViewmodel x:Key="MyResource"/>
<local:DeepSetter
x:Key="MyBehaviorSetter"
TargetProperty="Message"
BindingExport="{Binding MyMessage, Source={StaticResource MyResource}}"/>
</StackPanel.Resources>
...修改按钮的行为声明如下:
<local:MyBehavior local:DeepSetter.BindingImport="{StaticResource MyBehaviorSetter}"/>
更新 3
好消息:Silverlight 4 上将提供任何 DependecyObject 的数据绑定:http://timheuer.com/blog/archive/2009/11/18/whats-new-in-silverlight-4-complete-guide-new-features.aspx#dobind
【问题讨论】:
-
我使用带有 SL 4 的自定义 DP 的行为,我没有收到错误但未使用绑定,即永远不会调用源的 getter/setter。你试过了吗?
-
我被锁定在 SilverLight3 中,所以我创建了一个扩展方法,允许我从控件中提取行为并在其上设置所需的属性。它很hacky,但不能让它正常工作。
标签: silverlight silverlight-3.0