【问题标题】:WPF User Control Data Binding Not WorkingWPF 用户控件数据绑定不起作用
【发布时间】:2013-10-04 21:37:36
【问题描述】:

我正在创建一个简单的用户控件,将弹出窗口与文本视图结合起来,这并不疯狂。当我一开始在窗口中设置它以设置样式时,它工作得很好,但是当我将它移到用户控件中以实际完成它时,它就不能再正常工作了。

我将最小值和最大值传递给控件,​​然后它会自动创建一个数字列表以供从该范围内选择。在用户控件中,数字列表没有正确绑定,谁知道为什么。也许有人可以看看我的代码。

我已经阅读了很多关于此的其他问题,但我真的不知道发生了什么。我的输出窗口中没有任何错误,所以那里没有任何线索。无论如何,这是代码 -

UserControl.xaml

<UserControl x:Class="UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         x:Name="Me"
         DataContext="{Binding RelativeSource={RelativeSource Self}}">

<StackPanel>
    <TextBox Name="myTextbox"
             Height="30"
             Margin="0"
             FontSize="14"
             IsReadOnly="True"
             Padding="5,2"
             Text="{Binding Value}" />
    <Popup x:Name="myPopup"
           PlacementTarget="{Binding ElementName=myTextbox}"
           StaysOpen="True">
        <Popup.Style>
            <Style TargetType="{x:Type Popup}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=myTextbox, Path=IsFocused}" Value="True">
                        <Setter Property="IsOpen" Value="True" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Popup.Style>

        <StackPanel>
            <ListView Name="myListView"
                      Height="100"
                      MaxHeight="300"
                      ItemsSource="{Binding List,
                                            UpdateSourceTrigger=PropertyChanged}"
                      SelectionChanged="ListView_SelectionChanged">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Label Width="100"
                               Height="30"
                               Margin="0"
                               Content="{Binding}"
                               FontFamily="Segoe UI"
                               FontSize="14"
                               Padding="5,2" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <Button Width="200" Height="30" />
        </StackPanel>
    </Popup>

</StackPanel>

UserControl.xaml.vb

Imports System.ComponentModel
Imports System.Linq.Expressions
Imports System.Collections.ObjectModel

Class UserControl1

' Dependency Properties
Public Shared ReadOnly ListProperty As DependencyProperty = DependencyProperty.Register("List", GetType(ObservableCollection(Of Integer)), GetType(MainWindow))
Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(Integer), GetType(MainWindow))
Public Shared ReadOnly MaxValueProperty As DependencyProperty = DependencyProperty.Register("MaxValue", GetType(Integer), GetType(MainWindow))
Public Shared ReadOnly MinValueProperty As DependencyProperty = DependencyProperty.Register("MinValue", GetType(Integer), GetType(MainWindow))

' Properties
Public Property List As ObservableCollection(Of Integer)
    Get
        Return DirectCast(GetValue(ListProperty), ObservableCollection(Of Integer))
    End Get
    Set(value As ObservableCollection(Of Integer))
        SetValue(ListProperty, value)
    End Set
End Property

Public Property Value As Integer
    Get
        Return DirectCast(GetValue(ValueProperty), Integer)
    End Get
    Set(value As Integer)
        SetValue(ValueProperty, value)

    End Set
End Property

Public Property MaxValue As Integer
    Get
        Return DirectCast(GetValue(MaxValueProperty), Integer)
    End Get
    Set(value As Integer)
        SetValue(MaxValueProperty, value)
    End Set
End Property

Public Property MinValue As Integer
    Get
        Return DirectCast(GetValue(MinValueProperty), Integer)
    End Get
    Set(value As Integer)
        SetValue(MinValueProperty, value)
    End Set
End Property

Private Sub ListView_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
    Value = List(myListView.SelectedIndex)
End Sub

Private Sub UserControl1_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    List = New ObservableCollection(Of Integer)

    ' Add all available numbers into the list
    For iCounter As Integer = MinValue To MaxValue
        List.Add(iCounter)
    Next

    ' Set the selected index on the list for the value
    myListView.SelectedIndex = Value - MinValue
End Sub
End Class

仅供参考,当我对此进行测试时,我自己在窗口和用户控件设置中设置了最小值和最大值。

【问题讨论】:

    标签: wpf vb.net data-binding user-controls wpf-controls


    【解决方案1】:

    我认为您犯了与我刚开始学习 WPF 时相同的错误。我不能保证这你的问题的原因,但因为它是我能看到的唯一一个,我会解决它。不幸的是,有很多糟糕的教程和快速示例展示了 UserControl.DataContext 与自身的连接:

    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    

    或者:

    DataContext = this;
    

    现在,如果您想在外部将Bind 连接到UserControl,这是完全可以接受的,因为这是一种连接后面代码中定义的属性的快速简便的方法。但是,当您想从控件外部Bind 到属性时,您会发现问题。在这些情况下(如果不是在所有情况下),您应该在属性后面的代码中使用 RelativeSource BindingBind

    <TextBox Name="myTextbox" Height="30" Margin="0" FontSize="14" IsReadOnly="True"
        Padding="5,2" Text="{Binding Value, RelativeSource={RelativeSource AncestorType={
        x:Type UserControl1}}}" />
    

    在这个Binding 中,UserControl1 是声明属性的UserControl 的名称。这应该在所有内部Bindings 上完成。这样,DataContext没有设置为UserControl,但Bindings 仍然可以找到属性。

    您可以从 MSDN 上的 RelativeSource MarkupExtension 页面了解有关 RelativeSource 的更多信息。

    【讨论】:

      【解决方案2】:

      至于 Windows 应用程序(Windows 8 和 Windows 10 UWP) 方法是为您的控件命名并使用 Path 在您的 XAML 文件中引用它和元素名称

      <UserControl
      x:Class="MyControl"
      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"
      x:Name="Control"
      mc:Ignorable="d" >
      
         <Grid Height="240" VerticalAlignment="Top">
           <Rectangle Fill="{Binding ElementName=Control, Path=Background}" />
         </Grid>
      </UserControl>
      

      ``

      【讨论】:

        【解决方案3】:

        由于我无法向 Sheridan 提供好的答案,我必须提供一个新的答案,对此感到抱歉。

        虽然我喜欢这个解决方案

        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        

        它很快就失败了(正如 Sheridan 已经指出的那样)。

        您可以做的只是设置用户控件内容的 DataContext

        <UserControl x:Class="Example.View.Controls.MyUserControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:controls="clr-namespace:Example.View.Controls"
                 mc:Ignorable="d">
        <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls:MyUserControl}}}">
        
        </Grid>
        

        通过这种方式,所有以下绑定的样板代码都更少,因为您可以直接从代码隐藏中绑定到您的 DP,例如:

        <Label Content="{Binding MyLabel}"/>
        

        【讨论】:

        • 谢谢。存在同样的问题,这在 c# 中也是如此
        猜你喜欢
        • 1970-01-01
        • 2011-08-11
        • 2014-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多