简体   繁体   中英

Universal App XAML binding not working on UserControl when inside another UserControl

I'm currently working on a Windows Universal App. I'm still quite new to XAML in general but have had some experience with it.

The issue I'm having is around binding inside a UserControl. I've looked around and can't find an answer to my specific issue.

I have a XAML page that is linked to a ViewModel, this all works fine. Then on that page I'm using a UserControl that is basically just a panel with a header that contains some content. In the content of that panel I have another UserControl that basically just consists of a Label and TextBox.

When I bind things from my ViewModel to the ContentPanel UserControl everything works fine, it picks up my ViewModel context and binds correctly.

However, When I try to bind to the LabelledTextbox UserControl that is contained withing the ContentPanel the binding fails because it is just looking for the property that is on the ViewModel on the ContentPanel instead.

See below for the code I have

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();
    }
}

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

LabelledTextbox.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();
        }
    }

However, When I try to bind to the LabelledTextbox UserControl that is contained withing the ContentPanel the binding fails because it is just looking for the property that is on the ViewModel on the ContentPanel instead.

If I correctly understood what you've done, some properties of your ContentPanel are bound to the data model in the page's viewmodel, and properties of your LabelledTextbox are bound to the data model in other viewmodel?

If so, you can specify the DataContext for LabelledTextbox for StackPanel which is inside the ContentPanel , just for example like this:

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

In your page's viewmodel, you can make the data model for ContentPanel and initialize the data for example like this:

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

public string Heading { get; set; }

In the LabelledTextboxViewModel you can code for example like this:

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

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

Usually when we follow the MVVM pattern to develop a project, the data model should not be included inside of the viewmodel, I'm here just for clear and easy delivery , the key point is that you can specify different DataContext for different controls in the same page.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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