UWP MasterDetail control UserControl dependancy property

213 views Asked by At

I'm working on a master detail page created by the Windows Template Studio. I'm trying to have a comboBox in the userControl that defines the DetailsTemplate, which loads its values from a list in the page.

Here's the code:

ArticlesPage.xaml

<Page
x:Class="Estimates.Views.ArticlesPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Style="{StaticResource PageStyle}"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:model="using:Estimates.Models"
xmlns:views="using:Estimates.Views"
xmlns:fcu ="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)"
xmlns:cu ="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,5)"
mc:Ignorable="d">
<Page.Transitions>
    <TransitionCollection>
        <NavigationThemeTransition />
    </TransitionCollection>
</Page.Transitions>
<Page.Resources>
    <DataTemplate x:Key="ItemTemplate" x:DataType="model:Article">
        <Grid Height="64" Padding="0,8">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
                <TextBlock Text="{x:Bind Description, Mode=TwoWay}" Style="{ThemeResource ListTitleStyle}"/>
            </StackPanel>
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="DetailsTemplate" x:DataType="views:ArticlesPage">
        <views:ArticlesDetailControl MasterMenuItem="{Binding}" MeasureUnits="{x:Bind MeasureUnits}" />
    </DataTemplate>

    <DataTemplate x:Key="NoSelectionContentTemplate">
        <TextBlock x:Uid="Articles_NoSelection" Style="{StaticResource ListNoSelectionTextStyle}" />
    </DataTemplate>
</Page.Resources>

<Grid>

    <Grid.RowDefinitions>
        <RowDefinition x:Name="TitleRow" Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <TextBlock
        x:Uid="Articles_Title"
        x:Name="TitlePage"
        Margin="12,0,12,7"
        Style="{StaticResource PageTitleStyle}" />

    <controls:MasterDetailsView
        Grid.Row="1"
        x:Name="MasterDetailsViewControl"
        ItemsSource="{x:Bind Items}"
        SelectedItem="{x:Bind Selected, Mode=TwoWay}"
        ItemTemplate="{StaticResource ItemTemplate}"
        NoSelectionContentTemplate="{StaticResource NoSelectionContentTemplate}"
        BorderBrush="Transparent"
        DetailsTemplate="{StaticResource DetailsTemplate}" >
    </controls:MasterDetailsView>

    <Grid VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="0,15,0,0" Grid.Row="2">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Button x:Uid="AddButton" Grid.Column="0" Margin="5" Click="AddButton"/>
        <Button x:Uid="SaveButton" Grid.Column="1" Margin="5" Click="SaveButton"/>
        <Button x:Uid="DeleteButton" Grid.Column="2" Margin="5" Click="DeleteButton"/>
    </Grid>
    <!--  Adaptive triggers  -->
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="WindowStates">
            <VisualState x:Name="WideState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="640"/>
                </VisualState.StateTriggers>
            </VisualState>
            <VisualState x:Name="NarrowState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="TitlePage.Margin" cu:Value="60,0,12,7" fcu:Value="12,0,12,7"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

ArticlesPage.xaml.cs

    public sealed partial class ArticlesPage : Page, INotifyPropertyChanged
{
    private Article _selected;
    private ObservableCollection<MeasureUnit> _measureUnits;
    private IRepositoryService _repositoryService { get; set; }

    public Article Selected
    {
        get { return _selected; }
        set { Set(ref _selected, value); }
    }

    public ObservableCollection<MeasureUnit> MeasureUnits
    {
        get { return _measureUnits; }
        set { Set(ref _measureUnits, value);}
    }

    public ObservableCollection<Article> Items { get; private set; } = new ObservableCollection<Article>();

    public ArticlesPage()
    {
        InitializeComponent();
        Loaded += ArticlesPage_Loaded;
        _repositoryService = new RepositoryService();
    }

    private void ArticlesPage_Loaded(object sender, RoutedEventArgs e)
    {
        Items.Clear();

ArticledDetailControl.xaml

<UserControl
x:Class="Estimates.Views.ArticlesDetailControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:Estimates.Models"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<ScrollViewer Name="ForegroundElement" VerticalScrollMode="Enabled" HorizontalAlignment="Stretch" Padding="12,0">
    <StackPanel HorizontalAlignment="Stretch">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Margin="0,8,0,0">
            <TextBlock
                Margin="12,0,0,0"
                Text="{x:Bind MasterMenuItem.Description, Mode=TwoWay}"
                Style="{StaticResource SubheaderTextBlockStyle}" />
        </StackPanel>
        <StackPanel Name="block" Padding="0,15,0,0">
            <TextBox x:Uid="Description" Text="{x:Bind MasterMenuItem.Description, Mode=TwoWay}" />
            <TextBox x:Uid="Notes" Text="{x:Bind MasterMenuItem.Notes, Mode=TwoWay}" Margin="0,6,0,0"/>
            <Grid Margin="0,6,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.33*" />
                    <ColumnDefinition Width="0.33*" />
                    <ColumnDefinition Width="0.33*" />
                </Grid.ColumnDefinitions>
                <ComboBox x:Uid="MeasureUnits" x:Name="MeasureUnitsCB" ItemsSource="{x:Bind MeasureUnits}" Grid.Column="0">
                    <ComboBox.ItemTemplate>
                        <DataTemplate x:DataType="model:MeasureUnit">
                            <TextBlock Text="{x:Bind Description}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
                <TextBox x:Uid="Price" Text="{x:Bind MasterMenuItem.Price, Mode=TwoWay}" Grid.Column="2" />
            </Grid>
        </StackPanel>
    </StackPanel>
</ScrollViewer>

ArticlesDetailControl.xaml.cs

    public sealed partial class ArticlesDetailControl : UserControl
{
    public Article MasterMenuItem
    {
        get { return GetValue(MasterMenuItemProperty) as Article; }
        set { SetValue(MasterMenuItemProperty, value); }
    }

    public IEnumerable<MeasureUnit> MeasureUnits
    {
        get { return GetValue(MeasureUnitsProperty) as IEnumerable<MeasureUnit>; }
        set { SetValue(MeasureUnitsProperty, value); }
    }

    public static readonly DependencyProperty MasterMenuItemProperty =
        DependencyProperty.Register("MasterMenuItem", typeof(Article), typeof(ArticlesDetailControl), new PropertyMetadata(null, OnMasterMenuItemPropertyChanged));
    public static readonly DependencyProperty MeasureUnitsProperty =
        DependencyProperty.Register("MeasureUnits", typeof(IEnumerable<MeasureUnit>), typeof(ArticlesDetailControl), new PropertyMetadata(null, OnMeasureUnitsPropertyChanged));

    public ArticlesDetailControl()
    {
        InitializeComponent();
    }

    private static void OnMasterMenuItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as ArticlesDetailControl;
        control.ForegroundElement.ChangeView(0, 0, 1);
    }

    private static void OnMeasureUnitsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine("PD");
    }
}

So, the question is: How MasterMenuItem is populated? And why my property MeasureUnits it's not populated in the UserControl?

Edit: As suggested by TheZapper in the accepted answer, here's the implementation of OnMenuMasterItemPropertyChanged:

        private static void OnMasterMenuItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as ArticlesDetailControl;
        control.ForegroundElement.ChangeView(0, 0, 1);

        if (control.MasterMenuItem.MeasureUnit != null)
        {
            control.MeasureUnitsCB.SelectedItem =
                control.MeasureUnits.First(s => s.Id == control.MasterMenuItem.MeasureUnit.Id);
        }

        if (control.MasterMenuItem.VatCode != null)
        {
            control.VatCodesCB.SelectedItem =
                control.VatCodes.First(s => s.Id == control.MasterMenuItem.VatCode.Id);
        }
    }

I load the lists in the constructor of the UserControl.

1

There are 1 answers

1
thezapper On BEST ANSWER

I guess your problem results from binding to MasterMenuItemProperty in your UserControl

Maybe you could add DependencyProperties as Notes, Description in your user control and define your Template like this

<DataTemplate x:Key="DetailsTemplate" x:DataType="views:ArticlesPage">
    <views:ArticlesDetailControl Notes="{x:Bind Notes}" MeasureUnits="{x:Bind MeasureUnits}" />
</DataTemplate>

or you could try to update your bindings in the Changed-Event.

private static void OnMasterMenuItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = d as ArticlesDetailControl;
    control.ForegroundElement.ChangeView(0, 0, 1);
    *** Update Binding ***
}