C# - Template10 MVVM を使用する UWP で ContentDialog から別のページへのナビゲーションはどのように可能ですか?

okwaves2024-01-25  11

LoginPageCD.xaml

<ContentDialog
x:Class="ScanWorx.ContentDialogs.LoginPageCD"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ScanWorx.ContentDialogs"
xmlns:vm="using:ScanWorx.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="LoginPageContentD"
SecondaryButtonText="close"
SecondaryButtonClick="LoginPageContentD_SecondaryButtonClick">

<ContentDialog.Resources>
    <Thickness x:Key="ContentDialogPadding">16,16,16,16</Thickness>
    <vm:LoginPageCDViewModel x:Key="CDViewModel"  />
</ContentDialog.Resources>

<!--  Content Dialog Title  -->
<ContentDialog.TitleTemplate>
    <DataTemplate >

        <TextBlock
            HEADER DATA FOR TEMPLATE/>

    </DataTemplate>
</ContentDialog.TitleTemplate>

<ContentControl x:Name="LoginPageContentControl" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ContentControl.ContentTemplate>
        <DataTemplate>
            <Grid Width="500" Height="500">
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition Height="1*" />
                </Grid.RowDefinitions>

                <ComboBox
                    x:Name="Combobox_Login_test"
                    Grid.Row="0"
                    Header="Combobox_Login.Header"
                    IsEditable="True"
                    ItemsSource = "{Binding UserNameList, Source = {StaticResource CDViewModel}}" 
                    Text="{Binding Name, Source = {StaticResource CDViewModel},FallbackValue=DesigntimeValue, Mode=TwoWay}"/>

                <PasswordBox
                    x:Name="PasswordBox_Login"
                    Grid.Row="1"
                    Header="PasswordBox_Login.Header"
                    Password="{Binding Passwort, Mode=TwoWay , Source= {StaticResource CDViewModel}}" />

                <Button
                    x:Name="Button_Login_Click"
                    Grid.Row="2"
                    Command="{Binding LoginButtonCommand, Mode=TwoWay, Source= {StaticResource CDViewModel}}"
                    Style="{ThemeResource AccentButtonStyle}"/>

            </Grid>
        </DataTemplate>
    </ContentControl.ContentTemplate>
</ContentControl>

LoginPageCD.xaml.cs <== コードビハインド

using ScanWorx.ViewModels;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.ApplicationModel.Resources;
using Template10.Mvvm;

namespace ScanWorx.ContentDialogs
{

public partial class LoginPageCD : ContentDialog
{

    public LoginPResult Result { get; set; }

    public static ResourceLoader dict;
    public LoginPageCD()
    {
        this.InitializeComponent();
        ViewModelBase viewModelBase = new LoginPageCDViewModel();
        this.DataContext = viewModelBase;
        dict = ResourceLoader.GetForCurrentView("Login");
        LoginPageCDViewModel LPVM = new LoginPageCDViewModel();
        LPVM.UpdateUserNameList();
    }


    private void LoginPageContentD_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
    {
        Frame rootFrame = Window.Current.Content as Frame;
        rootFrame = new Frame();
        Window.Current.Content = rootFrame;
        rootFrame.Navigate(typeof(Views.LoginPage));

        LoginPageContentD.Hide();
       
    }

}
}

LoginPageCDViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Xml;
using Template10.Mvvm;
using Template10.Services.NavigationService;
using Windows.ApplicationModel.Resources;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Popups;
using Windows.UI.Xaml.Navigation;
using System.Linq;
using Windows.UI.Xaml;
using Template10.Utils;

namespace ScanWorx.ViewModels
{
class LoginPageCDViewModel : ViewModelBase
{
    public static ObservableCollection<string> _UserNameList = new ObservableCollection<string>();
    public ObservableCollection<string> UserNameList { get { return _UserNameList; } set { Set(ref _UserNameList, value); } }

    private string _Name = "";
    private string _Passwort = "";

    public RelayCommand LoginButtonCommand
    {
        get;
        private set;
    }

    public string Name { get { return _Name; } set { Set(ref _Name, value); } }
    public string Passwort { get { return _Passwort; } set { Set(ref _Passwort, value); } }


    public static ResourceLoader dict;

    public ObservableCollection<string> UpdateUserNameList()
    {
        try
        {
            **A FUNCTION TO UPDATE THE USER's LIST IN THE COMBOBOX**
            **USAGE: USED IN CODE BEHIND WHILE INITIALIZING THE CONTENT DIALOG**
        }
        catch
        {
            Debug.WriteLine("Catch Exeption:  LoginPage.xaml.cs     Invalid UserManagement.xml file");
        }
        return _UserNameList;
    }

    public LoginPageCDViewModel()
    {
        if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
        {
            Value = "Designtime value";
        }
        Services.SettingsServices.SettingsService.Instance.IsFullScreen = true;

        LoginButtonCommand = new RelayCommand(Button_Login_Click, () => true);

        dict = ResourceLoader.GetForCurrentView("Login");
    }
 
    public async void Button_Login_Click()
    {
        try
        {
                **ACTION: some code to check the username and password**

                loginPageCDViewModel.navigatetomain();        //<<<<// a function to navigate to main page which doesnt work     
                //NavigationService.Navigate(typeof(Views.MainPage));

        }
        catch
        {
            Debug.WriteLine("Catch Exeption:  LoginPageCDViewModel.cs     Button_Login_Click");
        }
    }

    public void navigatetomain()
    {
        Frame rootFrame = Window.Current.Content as Frame;
        rootFrame = new Frame();
        Window.Current.Content = rootFrame;
        rootFrame.Navigate(typeof(Views.MainPage));
        LoginPageContentD.Hide();

        //NavigationService.Navigate(typeof(Views.MainPage));

    }
}
}
上記の作業は私が試してみたものです。また、NavigationService.Navigate(typeof(Views.MainPage)); を使用してメイン ページに移動しようとしました。しかし、それも機能していません。 助けていただければ幸いです 関数 navigatetomain() を使用してメインページに移動できますが、Hide() を試みてもコンテンツ ダイアログが閉じません。また、ナビゲーション後、メインページにハンバーガーメニューが表示されず、空のメインページが表示されます。

注: Hide();閉じるボタンの背後にあるコードは完璧に機能します。



------------------------

コードを確認していますが、一部のコンテンツがコメントアウトされているようです。以下に私の考えをいくつか示します。

ViewModelの一意性を維持する

ContentDialog 関連のコードで 3 つの LoginPageCDViewModel、つまり ContentDialog.Resources、viewModelBase、LPVM を作成したことに気付きました。

これは混乱を引き起こす可能性があります。LoginPageCDViewModel のみを作成し、XAML でバインドできる DataContext として設定してみてください。

LoginPageContentD への不明な参照

ContentDialog を閉じようとすると、LoginPageContentD.Hide() というコードが使用されます。しかし、提供されたコードにはこの変数の定義が見つかりませんでした。

それは現在の ContentDialog を参照していますか?デバッグ ブレークポイントを使用してコードを追跡し、参照が正常かどうかを確認できます。

ContentDialog 内で呼び出される場合は、this.Hide() を直接使用できます。 これが現在の ContentDialog インスタンスを表す変数の場合は、ContentDialog の開始時に次のように値を割り当てる必要があります。
public LoginPageCD()
{
    this.InitializeComponent();
    ViewModelBase viewModelBase = new LoginPageCDViewModel();
    this.DataContext = viewModelBase;
    dict = ResourceLoader.GetForCurrentView("Login");
    viewModelBase.UpdateUserNameList();

    viewModelBase.LoginPageContentD = this;
}

上記の提案で問題を解決できない場合は、原因をテストして分析できるように、最小限の実行可能なデモ (個人情報は含まれていませんが、実行して問題を再現できるもの) を提供していただけますか?

4

わかりました、そうです、私のクエリは理解するのが難しくて申し訳ありません。コード全体を投稿しますので、お詫び申し上げます。問題は、2つのボタンがあるloginPage(投稿されたLoginPageCDについて話しているわけではありません)があるということです。 1 つは contentdialog(LoginPageCD) を呼び出すためのもので、もう 1 つは内部初期化目的です (このボタンはログインとは関係ありません)。ログインボタンを押すと、コンボボックス、パスワードボックス、ログインボタン、閉じるボタンがあるコンテンツダイアログが開きます。

– ファラーズ・ビルワデ

2020 年 9 月 3 日 13:56

つまり、基本的に、コンテンツ ダイアログを開くボタンのクリック関数は、loginPage のビューモデルと関数にバインドされています。navigatetomain() は、loginPageCDViewModel.cs ではなく、loginPageViewModel.cs に書かれています。これは、loginPageCD のインスタンスが、loginPageViewModel.cs に作成されるためです。これは、loginPage のボタンを押した後に、contentdialog を表示する必要があるためです。

– ファラーズ・ビルワデ

2020 年 9 月 3 日 14:02

ハンバーガー メニューが欠落していない適切なページに移動するには、ナビゲーションについて何が足りないのか教えていただけますか?

– ファラーズ・ビルワデ

2020 年 9 月 3 日 14:10

1

こんにちは。Template Studio の構成が同じかどうかはわかりません (ナビゲーション ペイン + MVVM ライトです)。同じ場合は、移動する前にページが ViewModelLocator.cs に登録されていることを確認してください。ハンバーガー メニューを保持したい場合は (ShellPage.xaml を意味している可能性があります)、NavigationService を自分で作成するのではなく、ShellViewModel.cs で NavigationService を呼び出して移動する必要があります。

– リチャード・チャン

2020 年 9 月 3 日 14:22



------------------------

独自のボタン [Button_Login_click] を使用する代わりに、contentdialog のprimarybuttonclick を使用し、LoginPageCDViewModel.cs で宣言されたrelaycommandを使用して、loginPageCDViewModel.cs で宣言されたrelaycommand ボタンにprimarybuttoncommand プロパティをバインドしました。

LoginPageCD.xaml は次のようになります

<ContentDialog
    x:Class="ScanWorx.ContentDialogs.LoginPageCD"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ScanWorx.ContentDialogs"
    xmlns:vm="using:ScanWorx.ViewModels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Name="LoginPageContentD"
    PrimaryButtonCommand="{x:Bind Path=vm:LoginPageViewModel.LoginButtonCommand }"
    PrimaryButtonText="Login"
    SecondaryButtonText="close"
    SecondaryButtonClick="LoginPageContentD_SecondaryButtonClick">
   .
   .
   .

そして、目的のページへのナビゲーションのために、content ダイアログ ボックスの結果を利用しています。つまり、ShowAsync(); を呼び出しています。アプリの開始時とプライマリクリックを認識した後、NavigationService.Navigate(typeof(Views.MainPage)); を使用しています。

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。