【问题标题】:How to setup datacontext and custom usercontrol binding如何设置数据上下文和自定义用户控件绑定
【发布时间】:2012-04-01 22:25:55
【问题描述】:

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

请你告诉我如何让绑定工作?

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 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>

用户控件的代码隐藏

#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

【问题讨论】:

  • 这是 WPF 问题还是 Silverlight 问题?
  • 我正在研究 Silverlight。但是上个月我在 WPF 上遇到了类似的问题,但是我做了一个没有绑定的解决方法。现在我想修复它,因为我确定,我只是错过了一小部分声明。我现在用不同的绑定关键字尝试了几个小时,但它从来没有奏效。
  • 我读了两遍这个问题,但仍然没有得到你想要做什么。提供您希望首先实现的目标的详细信息。
  • 感谢您的建议。我将通过图像更新问题。
  • 你为什么不喜欢模板,它们是显而易见的方式?

标签: wpf silverlight xaml binding user-controls


【解决方案1】:

编辑(插入):

您使用的是 Silverlight 4,而我可能在 Silverlight 5 或 WPF 中进行测试,但
WPF 肯定支持这种方式的 RelativeSourceBinding,但是您几乎正确。
中的输出窗口如果我是正确的,Visual Studio 会给你以下错误。

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

DataContext 将通过用户控件,但在用户控件的顶层/实例除外。
所以不要这样做:

<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}}" 覆盖绑定的数据上下文。删除它并且 Value 有效,因为您已将底层 DataContext 找回,但 Title 不再有效。

有一个解决办法:

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>

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

另外:

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

【讨论】:

  • 你好 Silvermind。感谢您的回答。我在用户控件上与您同在,但如果我在这里解释所有内容,它会扩展问题。我也只是为了提问而做了堆栈面板。我是 AncestorType 的新手,在输入 Silverlight XAML ucDbRow 时我已经收到错误消息,提示找不到 AncestorType 作为相对源。有什么建议吗?
  • @Nasenbaer 因为它需要你的命名空间。 xmnls:local="clr-namespace:mynamespace" 和 Ancestortype="{ x:Type local:ucDbRow}"
  • 顺便说一句:如果 ucDbRow 是 UserControl(如您的示例 xaml 中所示,我假设是),那么您还可以将单词 UserControl 指定为 AncestorType
  • 也许我的想法太小了。但是这些想法都不起作用:我仍然误解了在哪里更改某些内容以避免 XAML 解析器错误消息,同时将正确绑定到上下文。你能用更多代码更新你的示例吗?
  • 您是否完全复制了我提供的 XAML,因为它肯定可以工作?除非 ucDbRow 不是代码隐藏中的 UserControl,否则应该会导致更多(不同)错误。我现在没有时间创建一个完整的例子。也许在大约 6 小时内。
猜你喜欢
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 2012-07-19
  • 2011-04-27
  • 1970-01-01
  • 2016-03-15
  • 2011-01-18
  • 1970-01-01
相关资源
最近更新 更多