x:Bind a embeded page to the parent window viewmodel in WinUI 3

36 Views Asked by At

I'm working on a welcome screen and it can navigate 5 pages displayed using "Frame" control in the main window.

Now I need to x:Bind some controls to the viewmodel of main window cause I don't want to create 5 viewmodels for all 5 pages. So how to implement this? Or how to pass the view model object of main window to 5 pages

Main window: WelcomeScreen.xaml

<Window
    x:Class="WelcomeScreen.WelcomeScreen"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WelcomeScreen"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="">
    <Grid ColumnDefinitions="*,*,*" RowDefinitions="*" >
        <StackPanel Grid.Column="0" Grid.ColumnSpan="3" Orientation="Vertical" >
            <Frame x:Name="NavigationFrame" />
            <Line Stroke="LightGray" X1="0" Y1="0" X2="1200" Y2="0" StrokeThickness="2" Margin="12,0,12,0"/>
            <RelativePanel>
                <CheckBox x:Name="DoNotShowAaginCheckBox" Content="Don't show this again" FontFamily="{StaticResource VeneerFont}" Checked="{x:Bind ViewModel.OnChecked}" Unchecked="{x:Bind ViewModel.OnChecked}" Visibility="{x:Bind ViewModel.IsCheckBoxVisible,Mode=OneWay}" Margin="12,12,0,0" RelativePanel.AlignLeftWithPanel="True" />

            <Button x:Name="BackButton" Width="100" Style="{StaticResource AccentButtonStyle}" FontFamily="{StaticResource VeneerFont}" Click="{x:Bind ViewModel.BackButton_Click}" RelativePanel.AlignLeftWithPanel="True" Content="Back" Visibility="{x:Bind ViewModel.IsBackButtonVisible,Mode=OneWay}"  Margin="12,12,12,0"/>

            <PipsPager x:Name="PipsPager" Margin="0,15,0,0" NumberOfPages="{x:Bind ViewModel.WelcomeScreenPageList.Count}" SelectedPageIndex="{x:Bind ViewModel.CurrentPageIndex, Mode=TwoWay}" RelativePanel.AlignHorizontalCenterWithPanel="True" SelectedIndexChanged="Pager_SelectedIndexChanged" />

            <Button x:Name="NextButton" Width="100" Style="{StaticResource AccentButtonStyle}" FontFamily="{StaticResource VeneerFont}" Click="{x:Bind ViewModel.NextButton_Click}" Content="{x:Bind ViewModel.NextButtonText,Mode=OneWay}" RelativePanel.AlignRightWithPanel="True" Margin="0,12,12,0"/>
        </RelativePanel>
    </StackPanel>
</Grid>

WelcomeScreen.xaml.cs:

public sealed partial class WelcomeScreen : Window
{

    internal WelcomeScreenPageViewModel ViewModel { get; set; }

    public WelcomeScreen(object viewModel) : this()
    {
        if (viewModel == null || viewModel.GetType() != typeof(WelcomeScreenPageViewModel))
            return;

        ViewModel = viewModel as WelcomeScreenPageViewModel;
    }

    public WelcomeScreen()
    {
        this.InitializeComponent();
        this.InitializeControls();
    }

    public void Pager_SelectedIndexChanged(object sender,PipsPagerSelectedIndexChangedEventArgs e)
    {
        bool isForward = false;
        if (ViewModel.CurrentPageIndex > ViewModel.PreviousPageIndex)
           isForward = true;

        ViewModel.PreviousPageIndex = ViewModel.CurrentPageIndex;

        Type pagetype =   Type.GetType(ViewModel.WelcomeScreenPageList[ViewModel.CurrentPageIndex]);

        if (isForward)
        {
            NavigationFrame.Navigate(pagetype,
                       null,
                       new SlideNavigationTransitionInfo()
                       { Effect = SlideNavigationTransitionEffect.FromRight });
        }
        else
        {
            NavigationFrame.Navigate(pagetype,
                       null,
                       new SlideNavigationTransitionInfo()
                       { Effect = SlideNavigationTransitionEffect.FromLeft });
        }

        ViewModel.UpdateControls();

    }
}

Page1:

<Page
    x:Class="WelcomeScreen.WelcomeScreenPage1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WelcomeScreen"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource SystemControlBackgroundChromeWhiteBrush}">

    <Grid ColumnDefinitions="*" RowDefinitions="*,*" >
      HorizontalAlignment="Right" Grid.Row="0" Margin="0,5,5,0"/>
        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <TextBlock x:Name="PageText" Text="{x:Bind WelcomeScreenPageViewModel.xxx? , Mode=OneWay}""/>            
        </StackPanel>
    </Grid>
</Page>

WelcomeScreenPage1.xaml.cs:

public sealed partial class WelcomeScreenPage1 : Page
{
    public WelcomeScreenPage1()
    {
        this.InitializeComponent();
    }
}
1

There are 1 best solutions below

0
Andrew KeepCoding On BEST ANSWER

You can set the ViewModel right after the navigation:

Let's say you have 2 pages:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0">
        <Button
            Click="Page1Button_Click"
            Content="Page 1" />
        <Button
            Click="Page2Button_Click"
            Content="Page 2" />
    </StackPanel>
    <Frame
        x:Name="ContentFrame"
        Grid.Row="1" />
</Grid>
public sealed partial class Page1 : Page
{
    public Page1()
    {
        this.InitializeComponent();
    }

    public PageViewModel ViewModel { get; set; }
}
public sealed partial class Page2 : Page
{
    public Page2()
    {
        this.InitializeComponent();
    }

    public PageViewModel ViewModel { get; set; }
}

then you can do:

private void Page1Button_Click(object sender, RoutedEventArgs e)
{
    this.ContentFrame.Navigate(typeof(Page1));
    (this.ContentFrame.Content as Page1).ViewModel = new PageViewModel { Title = "Page 1" };
}

private void Page2Button_Click(object sender, RoutedEventArgs e)
{
    this.ContentFrame.Navigate(typeof(Page2));
    (this.ContentFrame.Content as Page2).ViewModel = new PageViewModel { Title = "Page 2" };
}