Contentdialog on startup

100 Views Asked by At

I am a total beginner with WinUI, but have some experience with C# and Windows Forms. I am trying out WinUI 3 for the first time and am trying to open a login window (ContentDialog) before the MainWindow loads. I am using the Template Studio for WinUI. And have created a test application.

I would like to open a ContentDialog when the program is started and a user logs in. At the moment it is only possible to open the dialog from a page (view) (see question from @WalderFrey and the answer from @mm8 to the Stackoverflow question (Link).

But this has the consequence that every time I click on the page, the login dialog appears.

How can I open the dialog at startup and only once without having to create a complicated logic. Is this possible in the MainWindow or via App.xaml?

Page1.xml

using System.Runtime.InteropServices;
using login_test.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;

namespace login_test.Views;

public sealed partial class page1Page : Page
{
    public page1ViewModel ViewModel
    {
        get;
    }

    public page1Page()
    {
        ViewModel = App.GetService<page1ViewModel>();
        InitializeComponent();

        this.Loaded += MainPage_Loaded;
    }

    private async void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        var dlg = new ContentDialog();
        dlg.XamlRoot = this.XamlRoot;
        dlg.Content = new LoginPage(); 
        
        dlg.PrimaryButtonText = "Login";
        dlg.CloseButtonText = "Cancel";
        dlg.DefaultButton = ContentDialogButton.Primary;

        var result = await dlg.ShowAsync();

        if (result == ContentDialogResult.Primary)
        {
        }
        else if (result == ContentDialogResult.Secondary)
        {
            Application.Current.Exit();
        }
        else
        {
            Application.Current.Exit();
        }
    }
}

LoginPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Page
    x:Class="login_test.Views.LoginPage"
    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:local="using:login_test.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="#00FFFFFF"
    mc:Ignorable="d">

    <StackPanel>
        <Image Width="130" Source="/Assets/RIAM_logo.png" />
        <TextBlock
            Margin="0,10,0,25"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontFamily="Arial Black"
            FontSize="26"
            Text="IMS Login" />
        <TextBox
            Name="usernameTB"
            Margin="5,0,5,10"
            PlaceholderText="Username" />
        <PasswordBox
            Name="passwordTB"
            Margin="5,0,5,0"
            PlaceholderText="Password" />
    </StackPanel>
</Page>
1

There are 1 best solutions below

3
Andrew KeepCoding On BEST ANSWER

As it's mentioned in the comments, the ContentDialog needs a XamlRoot. Unfortunately, Windows do not have a XamlRoot.

Since you just need a login window and you are using WinUIEx from the TemplateStudio, you can create a login window like this:

LoginWindow.xaml

<winex:WindowEx
    x:Class="LoginExample.LoginWindow"
    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:local="using:LoginExample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:winex="using:WinUIEx"
    mc:Ignorable="d">

    <StackPanel>
        <TextBox
            x:Name="UsernameTextBox"
            PlaceholderText="User name" />
        <PasswordBox
            x:Name="PasswordBox"
            PlaceholderText="Password" />
        <Button
            x:Name="LoginButton"
            Click="LoginButton_Click"
            Content="Login" />
    </StackPanel>
</winex:WindowEx>

LoginWindow.xaml.cs

namespace LoginExample;

public sealed partial class LoginWindow : WinUIEx.WindowEx
{
    private readonly IAuthenticationService _authenticationService;

    public LoginWindow(IAuthenticationService authenticationService)
    {
        this.InitializeComponent();
        _authenticationService = authenticationService;
    }

    public bool IsAuthenticated { get; private set; }

    private void LoginButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
    {
        IsAuthenticated = _authenticationService.Authenticate(
            this.UsernameTextBox.Text,
            this.PasswordBox.Password);

        if (IsAuthenticated is true)
        {
            Close();
        }
    }
}

IAuthenticationService.cs

public interface IAuthenticationService
{
    bool Authenticate(string username, string password);
}

AuthenticationService.cs

public class AuthenticationService : IAuthenticationService
{
    public bool Authenticate(string username, string password)
    {
        return username == "AndrewKeepCoding" && password == "1234";
    }
}

and in use it before you activate the MainWindow:

App.xaml.cs

public partial class App : Application
{
    private Window? _mainWindow;

    public App()
    {
        this.InitializeComponent();
    }

    protected override void OnLaunched(LaunchActivatedEventArgs args)
    {
        AuthenticationService authenticationService = new();

        var loginWindow = new LoginWindow(authenticationService)
        {
            Title = "Login",
            Width = 200,
            Height = 150,
            IsAlwaysOnTop = true,
            IsMaximizable = false,
            IsMinimizable = false,
            IsResizable = false,
        };

        loginWindow.CenterOnScreen();
        loginWindow.Closed += LoginWindow_Closed;

        loginWindow.Activate();
    }

    private void LoginWindow_Closed(object sender, WindowEventArgs args)
    {
        if (sender is LoginWindow { IsAuthenticated: true })
        {
            _mainWindow = new MainWindow();
            _mainWindow.Activate();
        }
    }
}