简体   繁体   中英

Data Binding in UWP User Controls using Template 10

I cannot get binding to work in my app with a user control. It is a UWP app with template 10.

I use the same bind in the mainpage as I do in the user control but the field in the user control does not react to changes. I have read several articles that tell me how to set the datacontent of my user control but I can not get any of them to work.

My code is as follows:

Mainpage.xaml

    Page x:Class="UserControlTest.Views.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
      xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
      xmlns:controls="using:Template10.Controls"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="using:UserControlTest.Views"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:vm="using:UserControlTest.ViewModels" mc:Ignorable="d">

    <Page.DataContext>
        <vm:MainPageViewModel x:Name="ViewModel" />
    </Page.DataContext>

    <RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

        <controls:PageHeader x:Name="pageHeader" Content="Main Page"
                             RelativePanel.AlignLeftWithPanel="True"
                             RelativePanel.AlignRightWithPanel="True"
                             RelativePanel.AlignTopWithPanel="True" />

        <TextBlock x:Name="mainTextBlock" Margin="16,16,16,16"
                   RelativePanel.AlignLeftWithPanel="True"
                   RelativePanel.Below="pageHeader" 
                   Text="{Binding TextToShow}" />

        <local:ShowText Margin="16,16,16,16"
            RelativePanel.Below="pageHeader"
            RelativePanel.AlignRightWithPanel="True"/>

        <Button Content="Change Text" Margin="16,16,16,16" 
                Command="{x:Bind ViewModel.ChangeText }" 
                RelativePanel.AlignLeftWithPanel="True" 
                RelativePanel.Below="mainTextBlock"/>
    </RelativePanel>

</Page>

MainPageViewModel.cs

    using System.Collections.Generic;
    using System;
    using System.Linq;
    using System.Threading.Tasks;
    using Windows.Security.Cryptography.Core;
    using Template10.Mvvm;
    using Template10.Services.NavigationService;
    using Windows.UI.Xaml.Navigation;

    namespace UserControlTest.ViewModels
    {
    public class MainPageViewModel : ViewModelBase
    {
        private string _textToShow = "Initial text";

        public string TextToShow
        {
            get { return _textToShow; }
            set { Set(ref _textToShow, value); }
        }

        DelegateCommand _changeText;

        public DelegateCommand ChangeText
            => _changeText ?? (_changeText = new DelegateCommand(ExecuteChangeTest, CanChangeText));

        private void ExecuteChangeTest()
        {
            TextToShow = "Changed text";
        }

        private bool CanChangeText()
        {
            return true;
        }
    }
}

ShowText.xaml

   <UserControl
    x:Class="UserControlTest.Views.ShowText"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UserControlTest.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="using:UserControlTest.ViewModels" mc:Ignorable="d">

    <UserControl.DataContext>
        <vm:MainPageViewModel x:Name="ViewModel" />
    </UserControl.DataContext>

    <Grid>
        <TextBlock x:Name="UserControlTextBlock"  
                   Text="{Binding TextToShow}" />
    </Grid>
</UserControl>

At first glance the problem is that your UserControl and your MainPage are using two different instances of ViewModel. When you create your static resource

        <vm:MainPageViewModel x:Name="ViewModel" />

You're creating an instance of MainPageViewModel. This means that when you set the value in from your MainPage instance of MainPageViewModel, it's not propagating to the second instance of MainPageViewModel that your UserControl created.

No worries though, we can fix this.

The DataContext of your user control should be set automatically to its parent's DataContext.

So Let's assume for a moment that you use your UserControl in your MainPage.xaml

 <Page.DataContext>
    <vm:MainPageViewModel x:Name="ViewModel" />
 </Page.DataContext>

 <MyUserControls:MyUserControl />

In this instance, MyUsercontrol is using the MainPageViewModel as it's DataContext. HOWEVER, this probably won't work, it's not a finished solution.

What you need to do is go to your UserControl's Xaml.CS and create a dependency property that you can bind to.

 public class MyUserControl : Control{

    public string MyControlsText
    {
        get { return (string)GetValue(MyControlsTextProperty); }
        set { SetValue(MyControlsTextProperty, value); }
    }

    public static readonly DependencyProperty MyControlsTextProperty = 
             DependencyProperty.Register("MyControlsText", typeof(string), 
                typeof(MyUserControl), new PropertyMetadata(String.Empty)); 

    }

Now that we have our dependency property, in our UserControl's Xaml we can bind to it.

<Grid>
    <TextBlock x:Name="UserControlTextBlock"  
               Text="{Binding MyControlsText}" />
</Grid>

And finally in our MainPage.Xaml we can finalize the binding

 <MyUserControls:MyUserControl MyControlsText="{Binding TextToShow}" />

So with the above code here is what we are accomplishing:

  • The DataContext is set in the MainPage.xaml and all of the children of MainPage.xaml share this DataContext
  • We created a dependency property in our UserControl that we can bind to
  • We bind the XAML of our UserControl to our dependency property
  • We Bind our view model's text property to our new user controls dependency property.

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