将Silverlight UserControl自定义属性绑定到其元素

时间:2009-04-08 12:15:40

标签: silverlight data-binding user-controls silverlight-2.0

我正在尝试在Silverlight 2.0中制作一个简单的填字游戏。我正在研究一个UserControl-ish组件,它代表了拼图中的一个正方形。我将UserControl的属性与其元素绑定在一起时遇到了麻烦。我终于(有点)让它工作了(可能对某些人有帮助 - 它花了我几个小时),但是想让它更“优雅”。

我想象它应该有一个内容区和一个标签(在右上角),可选地包含它的'数字。内容控件可能是TextBox,而标签控件可能是TextBlock。所以我用这个基本结构创建了一个UserControl(这个值在这个阶段是硬编码的):

    <UserControl x:Class="XWord.Square"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    FontSize="30" 
    Width="100" Height="100">
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1" 
                Text="7"/>
            <TextBox x:Name="Content" Grid.Row="1" Grid.Column="0"  
                Text="A"
                BorderThickness="0" />

        </Grid>
    </UserControl>

我还在Square类中创建了DependencyProperties,如下所示:

     public static readonly DependencyProperty LabelTextProperty;
     public static readonly DependencyProperty ContentCharacterProperty;

     // ...(static constructor with property registration, .NET properties
     // omitted for brevity)...

现在我想弄清楚如何将Label和Content元素绑定到两个属性。我是这样做的(在代码隐藏文件中):

     Label.SetBinding( TextBlock.TextProperty, new Binding { Source = this, Path = new PropertyPath( "LabelText" ), Mode = BindingMode.OneWay } );
     Content.SetBinding( TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath( "ContentCharacter" ), Mode = BindingMode.TwoWay } );

在XAML中做得更优雅。有谁知道这是怎么做的?

6 个答案:

答案 0 :(得分:19)

首先,使用{RelativeSource Self}:

在UserControl上设置DataContext
<UserControl x:Class="XWord.Square"  
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
FontSize="30"   
Width="100" Height="100" 
DataContext="{Binding RelativeSource={RelativeSource Self}}">

现在,您可以将各个元素绑定到usercontrol的属性:

<TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1" 
Text="{Binding LabelText}"/>  
<TextBox x:Name="Content" Grid.Row="1" Grid.Column="0" 
Text="{Binding ContentCharacter}" BorderThickness="0" />

对于SL 2.0,您需要在UserControl的Loaded事件处理程序上设置DataContext。

private void UserControl_Loaded( object sender, RoutedEventArgs e ) {
    LayoutRoot.DataContext = this;
}

答案 1 :(得分:7)

由于Silverlight无法使用FindAncestor技术,您可以使用类似于设置UserControl名称的技巧,但不会通过使用LayoutRoot的名称来破坏其功能...

<UserControl x:Class="XWord.Square"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FontSize="30" 
Width="100" Height="100">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <TextBlock x:Name="{Binding Path=Parent.LabelText, ElementName=LayoutRoot}" Grid.Row="0" Grid.Column="1" 
            Text="7"/>
        <TextBox x:Name="{Binding Path=Parent.ContentCharacter, ElementName=LayoutRoot}" Grid.Row="1" Grid.Column="0"  
            Text="A"
            BorderThickness="0" />
    </Grid>
</UserControl>

它在SL3中工作,无需添加任何其他代码(我在WP7应用程序中使用它),但不知道你是否可以在SL2中使用它。嗯,我现在意识到这个问题是如何陈旧的,希望它仍然有用,我来到这里是因为我在WP7中遇到同样问题的答案并没有说服我。

答案 2 :(得分:2)

我认为您正在寻找UI Element to Element Binding这是Silverlight 3的一项功能。

答案 3 :(得分:1)

我可能不完全理解你的问题。在Silverlight中,您可以绑定到几乎任何数据对象。因此,如果您有一个包含属性Content和Label的PuzzleSquare类,您可以直接从该对象绑定到这些属性。

假设您创建了一个简单的对象PuzzleSquare:

    public class PuzzleSquare
    {
      public string Content{ get; set; }
      public string Label{ get; set; }

      public void PuzzleSquare(){};
      public void PuzzleSquare(string label, string content):this()
      {
         Content = content;
         Label = label;
      }    
    }

因此,如果您使用经典视图/代码隐藏模型构建应用程序,您的代码将在页面加载时将此对象添加到网格的DataContext属性中:

LayoutRoot.DataContext = new PuzzleSquare("1", "A");

你的Xaml会绑定到Square属性:

    <TextBlock x:Name="Label" Grid.Row="0" Grid.Column="1" 
Text="{Binding Label}"/>            
    <TextBox x:Name="Content" Grid.Row="1" Grid.Column="0" 
Text="{Binding Content}" BorderThickness="0" />

这有意义吗?

IB。

答案 4 :(得分:0)

这适用于Silverlight 4.0

在UserControl上添加一个名称,然后在TextBlock中引用它

 <UserControl x:Class="XWord.Square"
    ...omitted for brevity ...
    x:Name="Square">

        <TextBlock x:Name="Label" ...
            Text="{Binding Path=LabelText,ElementName=Square}"/>

答案 5 :(得分:0)

试试这个:

Public ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(ButtonEdit), New System.Windows.PropertyMetadata("", AddressOf TextPropertyChanged))
Public Property Text As String
    Get
        Return GetValue(TextProperty)
    End Get
    Set(ByVal value As String)
        SetValue(TextProperty, value)
    End Set
End Property
Private Sub TextPropertyChanged()
    If String.IsNullOrEmpty(Text) Then
        TextBox1.Text = ""
    Else
        TextBox1.Text = Text
    End If
End Sub
Private Sub TextBox1_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles TextBox1.LostFocus
    Text = TextBox1.Text
End Sub

我可以在XAML和后面的代码中绑定。