繁体   English   中英

绑定到自定义控件后面的代码

[英]Binding to code behind from custom control

我有一个具有多个按钮的GridView。 以下模板定义了其中之一:

<DataTemplate x:Name="SubjectItemTemplate">
        <Canvas Width="340" Height="170" VerticalAlignment="Top">
            <Controls:ThreeImageButton HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0"
                                              NormalStateImageSource="{Binding NormalImage}"
                                              HoverStateImageSource="{Binding HoverImage}"
                                              PressedStateImageSource="{Binding PressedImage}" Command="{Binding Path=NavigateToUnitsPage}"
                CommandParameter="{Binding}" Canvas.Left="0" Canvas.Top="0">


        </Controls:ThreeImageButton>
    </Canvas>
</DataTemplate>

现在,您可以看到一个自定义控件,名为ThreeImageButton。 当我单独使用该按钮时,它可以正常工作。 但是,当我将其放在DataTemplate中时,它不会将属性绑定到后面的代码。

现在,我有

x:Name="MyThreeImageButton"

在自定义按钮定义中。 我这样连接到后面的代码:

<TextBlock Text="{Binding ElementName=MyThreeImageButton, Path=NormalStateImageSource}"/>

(这只是显示文本的测试,在实际代码中,我会将图像源分配给元素所引用的另一个属性)。

现在,TextBlock中什么也不显示。 我应该使用什么正确的绑定语法来访问属性?

谢谢!

编辑:我在InitializeComponent函数中设置变量,并且我在DependencyProperty上使用SetValue。

编辑:让我添加以下信息更加清楚

方案I:在GridView的DataTemplate中:

<UserControl CustomParameter="Literal Text">

在UserControl中:

<TextBlock Text="{Binding CustomParameter}">

在UserControl .cs中:this.DataContext =可行!

方案II:在GridView的DataTemplate中:

<UserControl CustomParameter="{Binding ValueFromDataItem">

在UserControl中:

<TextBlock Text="{Binding CustomParameter}">

在UserControl .cs中:this.DataContext =此功能!

我懂了,

因此,在用户控件中设置到自定义属性的双向绑定可能很棘手,因为用户控件无法绑定到CLR属性。 不仅如此,在用户控件上设置数据上下文还会对其内部的绑定产生意外影响。

您只需少量的代码即可解决这些问题。 基本上,使用依赖项属性来支持CLR属性,并在子元素而不是root用户控件上设置数据上下文。

看一下这个样本。 假设您有以下MainPage。 该MainPage最终将使用我们的自定义用户控件。 因此,让我们做好准备。

下面是代码:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = new /* your view model */
        {
            Title = Guid.NewGuid().ToString(),
        };
    }
}

在上面的代码中,我正在用一个简单的匿名类模拟一个复杂的视图模型。 像这样实现自己的想法对您来说很愚蠢,但同时对我来说,用一个完整的脚手架来构建一个简单的样本对我来说是愚蠢的。 我只是提出这一点,以免引起您的困惑-看起来我在产品中建议使用这种方法。

这是XAML:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <local:MyUserControl Text="{Binding Title}" />
</Grid>

在上面的XAML中,绝对没有什么特别的。 我已经在本地名称空间中引用了用户控件,我在这里简单地声明了它。

好的,现在我们有了控件的使用者,值得指出的是,在测试中,开发人员可能会误认为其绑定有效,因为他们使用文字值进行了测试。 文字值可以很好地绑定。 它与基础视图模型绑定在一起。

让我们说另一件事,一些开发人员倾向于避免依赖属性,因为需要更多的输入。 人们记得[kbd] propdp [/ kbd]是一个方便的Visual Studio代码段,为您提供了依赖项属性。

看一下这个用户控件。 它具有两个控件,一个TextBox和一个TextBlock,用于演示此绑定方法的OneWay和TwoWay功能。 我们还在用户控件上实现INotifyPropertyChanged。 在大多数情况下,在用户控件的情况下添加视图模型是过大的,因为用户控件已经像视图模型一样工作。 这取决于开发人员,但对我来说似乎很愚蠢。

这是背后的代码:

public sealed partial class MyUserControl : UserControl, INotifyPropertyChanged
{
    public MyUserControl()
    {
        this.InitializeComponent();
    }

    // text property

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValueDp(TextProperty, value); }
    }
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl), null);

    // bindable

    public event PropertyChangedEventHandler PropertyChanged;
    void SetValueDp(DependencyProperty property, object value,
        [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        SetValue(property, value);
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

在上面的颂歌中,我创建了一个“文本”属性,并使用依赖项属性对其进行支持。 出于重用的考虑,我还实现了SetValueDp(),如果我拥有多个属性,则可以一次又一次地使用它。 即使这个演示只有一个,但我还是想包含它,因为重复的逻辑当然应该像这样抽象出来。

这是XAML:

<Grid Background="Black" DataContext="{Binding ElementName=userControl}">
    <StackPanel>
        <TextBox Text="{Binding Text, Mode=TwoWay}"
            MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
        <TextBlock Text="{Binding Text}"
            MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
    </StackPanel>
</Grid>

在上面的XAML中,就绑定而言,我没有做任何特殊的事情。 语法仅使用适合控件的Mode绑定到Text属性。 就像您通常会做的一样。 但是,值得注意的是,未在用户控件上设置DataContext。 而是将其设置在网格上。 实际上,可以像这样使用树中除用户控件之外的任何控件。 只是不要设置用户控件的数据上下文。

顺便说一句。

我已经对其进行了测试,以确保它可以正常工作。 在此处演示一向和双向绑定都非常方便。 如果其他开发人员想要找到它而不发现这个问题,我什至可以将它变成一个博客。 感谢您的提问!

祝你好运!

正如所提到的注释一样,您的DataTemplate会将项目的数据上下文放置到要添加到列表中的任何对象上。 这与周围的用户控件的数据上下文不同。 如果要引用该datacontext的命令,请在DataTemplate的绑定中执行以下操作:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.NormalImage}

这就是说要出去找到用户控件的祖先,并使用它的datacontext,然后寻找NormalImage属性。 如果遇到问题,请检查输出窗口中是否存在绑定错误。 这对于发现绑定问题非常有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM