WPF 用户控件数据绑定不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19191200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:47:35  来源:igfitidea点击:

WPF User Control Data Binding Not Working

wpfvb.netdata-bindinguser-controlswpf-controls

提问by chris84948

I'm creating a simple User Control combining a popup with a text view, nothing crazy. When I set it up in a window at first to style it all out, it worked perfectly, but when I moved it into a User Control to actually finish it up, it won't work correctly any more.

我正在创建一个简单的用户控件,将弹出窗口与文本视图相结合,没什么疯狂的。当我首先在一个窗口中设置它以设置全部样式时,它运行得很好,但是当我将它移到用户控件中以实际完成它时,它将不再正常工作。

I pass a min and max value into the control and then it automatically creates a list of numbers to pick from in that range. In the User Control, the list of numbers doesn't get bound correctly, who knows why. Maybe someone can take a look at my code.

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

I've read a bunch of other questions about this, but don't really know what's happening. I'm not getting any errors in my output window, so no clues there. Anyway, here's the code -

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

UserControl.xaml

用户控件.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

用户控件.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

Just for reference, when I tested this out, I set the Min and Max values myself in both the window and usercontrol setup.

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

回答by Sheridan

I think that you have made the same mistake that I used to when I first started learning WPF. I can't guarantee that this isthe cause of your problem, but as it's the only one that I can see, I'll address it. Unfortunately, there are so many poor tutorials and quick examples that show the connecting of a UserControl.DataContextto itself:

我想你犯了和我刚开始学习 WPF 时一样的错误。我不能保证这您问题的原因,但由于这是我唯一能看到的问题,我会解决它。不幸的是,有太多糟糕的教程和快速示例显示了 aUserControl.DataContext与自身的连接:

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

Or:

或者:

DataContext = this;

Now this is perfectly acceptable if you don'twant to Bindto the UserControlexternally because it's a quick and easy way to connect with properties defined in the code behind. However, when you want to Bindto the properties from outside the control, you'll find problems. In these instances (if not on all occasions), you should use a RelativeSource Bindingto Bindto your code behind properties:

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

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

In this Binding, UserControl1is the name of the UserControlthat declared the properties. This should be done on all of the internal Bindings. This way, the DataContextis notset to the UserControl, but the Bindings still find the properties.

在 this 中BindingUserControl1UserControl声明属性的名称。这应该在所有内部Bindings 上完成。通过这种方式,DataContext不是设置为UserControl,但Binding仍然发现的属性。

You can find out more about RelativeSourcefrom the RelativeSource MarkupExtensionpage on MSDN.

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

回答by kkCosmo

As I cant provide a comment to Sheridan good answer I have to provide a new answer, sorry for this.

由于我无法对 Sheridan 的好答案发表评论,因此我必须提供一个新的答案,对此我深表歉意。

While I love this solution

虽然我喜欢这个解决方案

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

it fails (as Sheridan pointed out already) fast.

它很快就失败了(正如谢里丹指出的那样)。

What you can do is just set the DataContext of the content of your User Control

您可以做的只是设置用户控件内容的 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>

In this way all following Bindings have less Boilerplate code as you can just bind directly to your DP from the code-behind like:

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

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

回答by Daniel Veihelmann

As for Windows Apps (Windows 8 and Windows 10 UWP)the way to go is to give your control a name and reference it within your XAML file using Pathand ElementName:

至于Windows 应用程序(Windows 8 和 Windows 10 UWP),要走的路是为您的控件命名并使用PathElementName在您的 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>

``

``