Search code examples
c#wpfdata-bindinguwp

WPF binding to UserControl from Page


I have a UWP application, and it has a page containing a few textbox controls bound to A.B.C[2].D, A.B.C[2].E, A.B.C[2].F, and so on Now I want to move the text boxes to a separate UserControl to simplify my page's XAML but still want them to be bound to A.B.C[2].D, A.B.C[2].E etc. How can I achieve this?

Thank you

Here is my UserControl

<UserControl
    x:Class="Inspecto.HWStatusDisplayControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Truphase360"
    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="250">

    <Grid>
        <Grid.Resources>
            <Style x:Key="styleTxtBox" TargetType="TextBox">
                <Setter Property="IsReadOnly" Value="True" />
                <Setter Property="Width" Value="75"/>
            </Style>
            <Style x:Key="styleTxtBlk" TargetType="TextBlock">
                <Setter Property="FontSize" Value="12" />
                <Setter Property="Margin" Value="10"/>
                <Setter Property="Width" Value="75" />
            </Style>
        </Grid.Resources>
        <StackPanel Orientation="Vertical"  Margin="20">
            <TextBlock Text="{x:Bind Header}" FontSize="16" FontWeight="Bold" Margin="10">
            </TextBlock>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Temp1" Style="{StaticResource styleTxtBlk}" />
                <TextBox  Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=Temperature1 }" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Temp2" Style="{StaticResource styleTxtBlk}" />
                <TextBox  Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=Temperature2 }" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="SW Version" Style="{StaticResource styleTxtBlk}" />
                <TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=SWVersionStr }" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="HW Version" Style="{StaticResource styleTxtBlk}" />
                <TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=HWVersionStr }" />
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>

The code block directly under exists inside a page and is repeated multiple times. The TextBoxs' were bound to {x:Bind ViewModel.DeviceData.Status.Devices[0].Temperature1 } and so on inside the Page Now I want to display the same from UserControl.

In the data object, the instance of Devices[] is replaced every few seconds. The new array was created by deserializing from JSON object and directly assigned to like ViewModel.DeviceData.Status.Devices = FromJSON(string);

Thank you


Solution

  • I agree with @EldHasp. The solution for your scenario is that you might need to create a custom dependency property in the UserControl. Then pass the A.B.C object to this property of the UserControl via binding.

    I've made a simple demo about this, you could take look at the code and adjust it for your scenario.

    UserControl XAML

     <Grid x:Name="MyGrid">
        <Grid.Resources>
            <Style x:Key="styleTxtBox" TargetType="TextBox">
                <Setter Property="IsReadOnly" Value="True" />
                <Setter Property="Width" Value="75"/>
            </Style>
            <Style x:Key="styleTxtBlk" TargetType="TextBlock">
                <Setter Property="FontSize" Value="12" />
                <Setter Property="Margin" Value="10"/>
                <Setter Property="Width" Value="75" />
            </Style>
        </Grid.Resources>
        <StackPanel Orientation="Vertical"  Margin="20">
            <TextBlock Text="{x:Bind Header}" FontSize="16" FontWeight="Bold" Margin="10">
            </TextBlock>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Temp1" Style="{StaticResource styleTxtBlk}" />
                <TextBox  Style="{StaticResource styleTxtBox}" Text="{Binding MyDependencyProperty._List[0].Name}" />
            </StackPanel>
        </StackPanel>
    </Grid>
    

    UserControl Code

     public AClass MyDependencyProperty
        {
            get { return (AClass)GetValue(MyDependencyPropertyProperty); }
            set { SetValue(MyDependencyPropertyProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for MyDependencyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyDependencyPropertyProperty =
            DependencyProperty.Register("MyDependencyProperty", typeof(AClass), typeof(TestUserControl), new PropertyMetadata(null));
    
        public string Header = "TestHeader";
    
        public TestUserControl()
        {
            this.InitializeComponent();
    
            this.DataContext = this;
        }
    

    MainPage Xaml

     <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Foreground="Red" Text="{x:Bind ViewModel._AClass._List[1].Name}"/>
        
        <local:TestUserControl Grid.Row="1" MyDependencyProperty="{x:Bind ViewModel._AClass}"/>
    </Grid>
    

    MainPage Code

     public sealed partial class MainPage : Page
    {
        public TestViewModel ViewModel { get; set; }
    
        public MainPage()
        {
            this.InitializeComponent();
            ViewModel= new TestViewModel();
        }
    }
    
    public class TestViewModel 
    {
        public AClass _AClass { get; set; }
    
        public TestViewModel()
        {
            _AClass = new AClass();
        }
    }
    
    public class AClass
    {
        public List<BClass> _List { get; set; }
    
        public AClass()
        {
            _List = new List<BClass>();
            _List.Add(new BClass { Name = "123" });
            _List.Add(new BClass { Name = "234" });
        }
    }
    
    public class BClass
    {
         public string Name { get; set; }
    }
    

    And the result: enter image description here