如何设置datacontext和自定义usercontrol绑定

时间:2012-03-16 11:12:32

标签: wpf silverlight xaml binding user-controls

我不明白为什么绑定适用于文本框但不适用于usercontrol。 在下图中,您可以看到它应该如何工作。该服务可以绑定到黄色用户控件,此usercontrol包含我自己的类的属性。在我的情况下,此属性称为电子邮件。问题是,此电子邮件永远不会绑定到黄色用户控件。 如果我用简单的“ TextBox ”控件替换usercontrol,它就可以正常工作。

请您告诉我如何获得Binding工作?

User control description of binding

Silvelright主页的代码隐藏

#Region "UserProfile"

    ''' <summary>
    ''' UserProfile Dependency Property
    ''' </summary>
    Public Shared ReadOnly UserProfileProperty As DependencyProperty = _
        DependencyProperty.Register("UserProfile", GetType(ServiceReference1.UserProfile), GetType(MainPage), _
            New Windows.PropertyMetadata(Nothing, _
                AddressOf OnUserProfileChanged))

    ''' <summary>
    ''' Gets or sets the UserProfile property.  This dependency property 
    ''' indicates ....
    ''' </summary>
    Public Property UserProfile() As ServiceReference1.UserProfile
        Get
            Return CType(GetValue(UserProfileProperty), ServiceReference1.UserProfile)
        End Get
        Set(ByVal value As ServiceReference1.UserProfile)
            SetValue(UserProfileProperty, value)
        End Set
    End Property

    ''' <summary>
    ''' Handles changes to the UserProfile property.
    ''' </summary>
    Private Overloads Shared Sub OnUserProfileChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim target As MainPage = CType(d, MainPage)
        Dim oldUserProfile As ServiceReference1.UserProfile = CType(e.OldValue, ServiceReference1.UserProfile)
        Dim newUserProfile As ServiceReference1.UserProfile = target.UserProfile
        target.OnUserProfileChanged(oldUserProfile, newUserProfile)
    End Sub

    ''' <summary>
    ''' Provides derived classes an opportunity to handle changes to the UserProfile property.
    ''' </summary>
    Protected Overridable Overloads Sub OnUserProfileChanged(ByVal oldUserProfile As ServiceReference1.UserProfile, ByVal newUserProfile As ServiceReference1.UserProfile)
        Me.DataContext = newUserProfile

    End Sub

#End Region

在跟踪属性时,“newUserProfile”项在代码隐藏中成功设置。

XAML

<UserControl x:Class="CH_App.ucUserEditor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                          xmlns:my="clr-namespace:CH_App"

    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox Text="{Binding Path=Email}"/>
        <my:ucDbRow Title="Email" Value="{Binding Path=Email, Mode=TwoWay}" />
    </Grid>
</UserControl>

带有电子邮件绑定的Texbox可以像它应该的那样工作并显示电子邮件地址。 usercontrol不显示电子邮件地址。用户控件显示标题正确。

用户控件

<UserControl x:Class="CH_App.ucDbRow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:my="clr-namespace:CH_App"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
            DataContext="{Binding RelativeSource={RelativeSource Self}}"
    d:DesignHeight="300" d:DesignWidth="400">

    <StackPanel>
        <TextBlock x:Name="txtTitle" Text="{Binding Path=Title}" />
        <TextBox x:Name="txtValue" Text="{Binding Path=Value, Mode=TwoWay}"/>
    </StackPanel>
</UserControl>

usercontrol的代码隐藏

#Region "Title"

    ''' <summary>
    ''' Title Dependency Property
    ''' </summary>
    Public Shared ReadOnly TitleProperty As DependencyProperty = _
        DependencyProperty.Register("Title", GetType(String), GetType(ucDbRow), _
            New Windows.PropertyMetadata(""))

    ''' <summary>
    ''' Gets or sets the Title property.  This dependency property 
    ''' indicates ....
    ''' </summary>
    Public Property Title() As String
        Get
            Return CType(GetValue(TitleProperty), String)
        End Get
        Set(ByVal value As String)
            SetValue(TitleProperty, value)
        End Set
    End Property

#End Region



#Region "Value"

    ''' <summary>
    ''' Value Dependency Property
    ''' </summary>
    Public Shared ReadOnly ValueProperty As DependencyProperty = _
        DependencyProperty.Register("Value", GetType(String), GetType(ucDbRow), _
            New Windows.PropertyMetadata(""))

    ''' <summary>
    ''' Gets or sets the Value property.  This dependency property 
    ''' indicates ....
    ''' </summary>
    Public Property Value() As String
        Get
            Return CType(GetValue(ValueProperty), Object)
        End Get
        Set(ByVal value As String)
            SetValue(ValueProperty, value)
        End Set
    End Property

#End Region

1 个答案:

答案 0 :(得分:2)

编辑(插入):

你正在使用Silverlight 4,我要么在Silverlight 5或WPF中进行测试,但两者都可能,但是WPF当然支持RelativeSourceBinding,但是你几乎没有。左边输出如果我是正确的,Visual Studio中的窗口会出现以下错误。

  

System.Windows.Data错误:BindingExpression路径错误:
  'VisualBasicSilverlightApplication1.ucDbRow'上找不到'电子邮件'属性   'VisualBasicSilverlightApplication1.ucDbRow'(HashCode = 72766)。
  BindingExpression:Path ='DataContext.Email'
  DataItem ='VisualBasicSilverlightApplication1.ucDbRow'(HashCode = 72766);
  target元素是'VisualBasicSilverlightApplication1.ucDbRow'(Name ='');
  target属性是'Value'(类型'System.String')..

DataContext将通过usercontrol进行处理,除了usercontrol的toplevel / instance之外。
所以不要这样做:

<my:ucDbRow Title="Email" Value="{Binding Path=Email, Mode=TwoWay}" />

您需要在代码中更改的唯一内容是指向设置DataContext的元素,大多数情况下是LayoutRoot: (在ucUserEditor中)

<my:ucDbRow Title="Email" Value="{Binding ElementName=LayoutRoot, 
            Path=DataContext.Email, Mode=TwoWay}" />

上一个回答
您在CH_App.ucDbRow中使用此DataContext="{Binding RelativeSource={RelativeSource Self}}"覆盖绑定的datacontext。删除它并且Value有效,因为您已经将DataContext置于保留状态,但标题不再有效。

有一个解决方案:

ucDbRow更改为:

<UserControl x:Class="CH_App.ucDbRow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding}">
    <StackPanel>
      <TextBlock x:Name="txtTitle" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}" Height="23"/>
      <TextBox x:Name="txtValue" Text="{Binding Path=Value, Mode=TwoWay}"/>
    </StackPanel>
  </Grid>
</UserControl>

注意:如果Bindings不起作用,请检查您的输出窗口,如果它在输出窗口中失败,则检查。

另外:

我建议使用usercontrol作为控件。在我看来,usercontrols应该更多地用于表示单个上下文,而不是一半上下文中的一半上下文。开始将usercontrols更多地视为页面,并使用自定义控件和datatemplate进行详细工作。使用Grid构建更好的布局变得非常容易,这是(在我看来)WPF和Silverlight中最好的功能之一,不能被有序的用户控件打败。