【问题标题】:Universal App XAML binding not working on UserControl when inside another UserControl在另一个 UserControl 中时,通用应用程序 XAML 绑定在 UserControl 上不起作用
【发布时间】:2016-09-23 08:08:26
【问题描述】:

我目前正在开发一个 Windows 通用应用程序。总的来说,我对 XAML 还是很陌生,但对它有一些经验。

我遇到的问题是围绕用户控件内部的绑定。我环顾四周,找不到特定问题的答案。

我有一个链接到 ViewModel 的 XAML 页面,这一切都很好。然后在那个页面上,我使用了一个 UserControl,它基本上只是一个带有包含一些内容的标题的面板。在该面板的内容中,我有另一个用户控件,它基本上只包含一个标签和文本框。

当我将 ViewModel 中的内容绑定到 ContentPanel UserControl 时,一切正常,它会获取我的 ViewModel 上下文并正确绑定。

但是,当我尝试绑定到 ContentPanel 中包含的 LabelledTextbox UserControl 时,绑定失败,因为它只是在 ContentPanel 上的 ViewModel 上查找属性。

下面是我的代码

Page.xaml

<!--Page.xaml-->                    
<cc:ContentPanel PanelHeading="LEFT FOOT: Measurements" PanelHeadingBackground="{StaticResource OPCare.PanelHeader}">
                    <StackPanel>
                        <cc:LabelledTextbox LabelText="Malleoli Width" Text="test" />
                        <cc:LabelledTextbox LabelText="Met Head Width" />
                    </StackPanel>
                </cc:ContentPanel>

ContentPanel.xaml

<!--ContentPanel UserControl-->
<UserControl
    x:Class="OrthoticTabletApp.Controls.ContentPanel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:OrthoticTabletApp.Controls"
    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"
    x:Name="Parent">

    <Grid DataContext="{Binding ElementName=Parent}">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Grid Padding="10" Grid.Column="0" Grid.Row="0" Height="50" Background="{Binding Path=PanelHeadingBackground}">
            <TextBlock Height="30" LineHeight="30" Text="{Binding Path=PanelHeading}" />
        </Grid>

        <Grid Padding="10" Grid.Column="0" Grid.Row="1" Background="White">
            <ContentPresenter Content="{Binding Path=PanelBody}" />
        </Grid>

    </Grid>
</UserControl>

ContentPanel.xaml.cs

[ContentProperty(Name = "PanelBody")]

public sealed partial class ContentPanel : UserControl
{

    public static readonly DependencyProperty PanelHeadingProperty = DependencyProperty.Register("PanelHeading", typeof(string), typeof(ContentPanel), new PropertyMetadata(""));

    public string PanelHeading
    {
        get
        {
            return (string)GetValue(PanelHeadingProperty);
        }
        set
        {
            SetValue(PanelHeadingProperty, value);
        }
    }

    public static readonly DependencyProperty PanelBodyProperty = DependencyProperty.Register("PanelBody", typeof(object), typeof(ContentPanel), new PropertyMetadata(null));

    public object PanelBody
    {
        get
        {
            return (object)GetValue(PanelBodyProperty);
        }
        set
        {
            SetValue(PanelBodyProperty, value);
        }
    }

    public Brush PanelHeadingBackground
    {
        get { return (Brush)GetValue(PanelHeadingBackgroundProperty); }
        set { SetValue(PanelHeadingBackgroundProperty, value); }
    }

    public static readonly DependencyProperty PanelHeadingBackgroundProperty =
        DependencyProperty.Register("PanelHeadingBackground", typeof(Brush), typeof(ContentPanel), new PropertyMetadata(null));

    public ContentPanel()
    {
        this.InitializeComponent();
    }
}

LabeledTextbox.xaml

<UserControl
    x:Class="OrthoticTabletApp.Controls.LabelledTextbox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:OrthoticTabletApp.Controls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="50"
    d:DesignWidth="400"
    x:Name="Parent">

    <Grid DataContext="{Binding ElementName=Parent}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Grid Grid.Column="0" Padding="10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="15" />
            </Grid.ColumnDefinitions>

            <TextBlock Grid.Column="0" Text="{Binding Path=LabelText}" />

        </Grid>

        <Grid Grid.Column="1" Padding="10">
            <TextBox Text="{Binding Path=Text}" />
        </Grid>
    </Grid>
</UserControl>

LabeledTextbox.xaml.cs

public sealed partial class LabelledTextbox : UserControl
    {
        public string LabelText
        {
            get { return (string)GetValue(LabelTextProperty); }
            set { SetValue(LabelTextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LabelText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LabelTextProperty =
            DependencyProperty.Register("LabelText", typeof(string), typeof(LabelledTextbox), new PropertyMetadata(null));

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(LabelledTextbox), new PropertyMetadata(null));

        public LabelledTextbox()
        {
            this.InitializeComponent();
        }
    }

【问题讨论】:

  • &lt;Grid DataContext="{Binding ElementName=Parent}"&gt; - 这是您将当前用户控件设置为 DataContext 的地方,这就是为什么它在 UserControl 中寻找绑定属性而不是在视图模型中。 LabelledTextBox.xaml 和 ContentPanel.xaml 中都有同样的问题。如果您删除DataContext="{Binding ElementName=Parent}",那么它应该可以工作。另外,您在哪里为 Page.xaml 设置 DataContext

标签: c# xaml user-controls win-universal-app


【解决方案1】:

但是,当我尝试绑定到 ContentPanel 中包含的 LabelledTextbox UserControl 时,绑定失败,因为它只是在 ContentPanel 上的 ViewModel 上查找属性。

如果我正确理解您所做的,您的ContentPanel 的某些属性绑定到页面视图模型中的数据模型,而您的LabelledTextbox 的属性绑定到其他视图模型中的数据模型?

如果是这样,您可以为StackPanel 指定DataContextLabelledTextbox,它位于ContentPanel 内,例如:

<cc:ContentPanel PanelHeading="{x:Bind Heading}" PanelHeadingBackground="Azure">
    <StackPanel>
        <StackPanel.DataContext>
            <local:LabelledTextboxViewModel x:Name="VM" />
        </StackPanel.DataContext>
        <cc:LabelledTextbox LabelText="{x:Bind VM.Lable1}" Text="test" />
        <cc:LabelledTextbox LabelText="{x:Bind VM.Lable2}" />
    </StackPanel>
</local:ContentPanel>

在页面的视图模型中,您可以为ContentPanel 制作数据模型并初始化数据,例如:

public BlankPage3ViewModel()
{
    Heading = "LEFT FOOT: Measurements";
}

public string Heading { get; set; }

在 LabelledTextboxViewModel 中,您可以编写如下代码:

public class LabelledTextboxViewModel 
{
    public LabelledTextboxViewModel()
    {
        Lable1 = "Malleoli Width";
        Lable2 = "Met Head Width";
    }

    public string Lable1 { get; set; }
    public string Lable2 { get; set; }
}

通常我们在按照MVVM模式开发项目的时候,数据模型不应该包含在viewmodel里面,我这里只是为了清晰易交付,关键是您可以为同一页面中的不同控件指定不同的DataContext

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-29
    相关资源
    最近更新 更多