110

を使用してログインを作成し、作成中のアプリケーションwindow controlにユーザーがログインできるようにします。WPF

ここまでで、ユーザーがログイン画面のusernamepasswordに正しい資格情報を入力したかどうかを確認するメソッドを作成しました。textboxbindingproperties

boolメソッドを作成することでこれを達成しました。

public bool CheckLogin()
{
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome " + user.Username + ", you have successfully logged in.");

        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
}

public ICommand ShowLoginCommand
{
    get
    {
        if (this.showLoginCommand == null)
        {
            this.showLoginCommand = new RelayCommand(this.LoginExecute, null);
        }
        return this.showLoginCommand;
    }
}

private void LoginExecute()
{
    this.CheckLogin();
} 

私も同じようcommandbind自分のボタンを押しています。xaml

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" />

ユーザー名とパスワードを入力すると、正しいか間違っているかにかかわらず、割り当てられたコードが実行されます。しかし、ユーザー名とパスワードの両方が正しい場合、ViewModel からこのウィンドウを閉じるにはどうすればよいでしょうか?

以前に a を使用してみましたdialog modalが、うまくいきませんでした。さらに、私の app.xaml 内で、次のようなことを行いました。これは、最初にログイン ページをロードし、次に true になると、実際のアプリケーションをロードします。

private void ApplicationStart(object sender, StartupEventArgs e)
{
    Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;

    var dialog = new UserView();

    if (dialog.ShowDialog() == true)
    {
        var mainWindow = new MainWindow();
        Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
        Current.MainWindow = mainWindow;
        mainWindow.Show();
    }
    else
    {
        MessageBox.Show("Unable to load application.", "Error", MessageBoxButton.OK);
        Current.Shutdown(-1);
    }
}

Window control質問: ViewModel からログインを閉じるにはどうすればよいですか?

前もって感謝します。

4

18 に答える 18

173

を使用してウィンドウを ViewModel に渡すことができますCommandParameter。以下の私の例を参照してください。

CloseWindowWindows をパラメーターとして受け取り、それを閉じるメソッドを実装しました。ウィンドウは を介し​​て ViewModel に渡されますCommandParameterx:Name閉じる必要があるウィンドウの を定義する必要があることに注意してください。私の XAML ウィンドウでは、このメソッドを経由Commandして呼び出し、ウィンドウ自体をパラメーターとして ViewModel を使用して渡しますCommandParameter

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}"

ビューモデル

public RelayCommand<Window> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
}

private void CloseWindow(Window window)
{
    if (window != null)
    {
       window.Close();
    }
}

意見

<Window x:Class="ClientLibTestTool.ErrorView"
        x:Name="TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:localization="clr-namespace:ClientLibTestTool.ViewLanguages"
        DataContext="{Binding Main, Source={StaticResource Locator}}"
        Title="{x:Static localization:localization.HeaderErrorView}"
        Height="600" Width="800"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen">
    <Grid> 
        <Button Content="{x:Static localization:localization.ButtonClose}" 
                Height="30" 
                Width="100" 
                Margin="0,0,10,10" 
                IsCancel="True" 
                VerticalAlignment="Bottom" 
                HorizontalAlignment="Right" 
                Command="{Binding CloseWindowCommand, Mode=OneWay}" 
                CommandParameter="{Binding ElementName=TestWindow}"/>
    </Grid>
</Window>

私はMVVMライトフレームワークを使用していますが、プリンシパルはすべてのwpfアプリケーションに適用されることに注意してください。

ビューモデルは UI 実装について何も認識してはならないため、このソリューションは MVVM パターンに違反しています。MVVM プログラミング パラダイムに厳密に従いたい場合は、ビューの型をインターフェイスで抽象化する必要があります。

MVVM適合ソリューション(旧EDIT2)

ユーザーCronoは、コメント セクションで有効な点について言及しています。

Window オブジェクトをビュー モデルに渡すと、MVVM パターンの IMHO が壊れます。なぜなら、それが表示されているものを vm に強制的に認識させるためです。

これは、close メソッドを含むインターフェースを導入することで修正できます。

インターフェース:

public interface ICloseable
{
    void Close();
}

リファクタリングされた ViewModel は次のようになります。

ビューモデル

public RelayCommand<ICloseable> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<IClosable>(this.CloseWindow);
}

private void CloseWindow(ICloseable window)
{
    if (window != null)
    {
        window.Close();
    }
}

ICloseableビューでインターフェイスを参照して実装する必要があります

表示 (コード ビハインド)

public partial class MainWindow : Window, ICloseable
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

元の質問への回答: (以前の EDIT1)

あなたのログインボタン (追加された CommandParameter):

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" CommandParameter="{Binding ElementName=LoginWindow}"/>

あなたのコード:

 public RelayCommand<Window> CloseWindowCommand { get; private set; } // the <Window> is important for your solution!

 public MainViewModel() 
 {
     //initialize the CloseWindowCommand. Again, mind the <Window>
     //you don't have to do this in your constructor but it is good practice, thought
     this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
 }

 public bool CheckLogin(Window loginWindow) //Added loginWindow Parameter
 {
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome "+ user.Username + ", you have successfully logged in.");
        this.CloseWindow(loginWindow); //Added call to CloseWindow Method
        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
 }

 //Added CloseWindow Method
 private void CloseWindow(Window window)
 {
     if (window != null)
     {
         window.Close();
     }
 }
于 2013-04-24T14:56:25.413 に答える
14

さて、ここに私がいくつかのプロジェクトで使用したものがあります。ハックのように見えるかもしれませんが、うまく機能します。

public class AttachedProperties : DependencyObject //adds a bindable DialogResult to window
{
    public static readonly DependencyProperty DialogResultProperty = 
        DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(AttachedProperties), 
        new PropertyMetaData(default(bool?), OnDialogResultChanged));

    public bool? DialogResult
    {
        get { return (bool?)GetValue(DialogResultProperty); }
        set { SetValue(DialogResultProperty, value); }
    }

    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window == null)
            return;

        window.DialogResult = (bool?)e.NewValue;
    }
}

DialogResultVM にバインドし、プロパティの値を設定できるようになりました。Window値が設定されると、 が閉じます。

<!-- Assuming that the VM is bound to the DataContext and the bound VM has a property DialogResult -->
<Window someNs:AttachedProperties.DialogResult={Binding DialogResult} />

これは、本番環境で実行されているものの要約です

<Window x:Class="AC.Frontend.Controls.DialogControl.Dialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl" 
        xmlns:hlp="clr-namespace:AC.Frontend.Helper"
        MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
        WindowStartupLocation="CenterScreen" Title="{Binding Title}"
        hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True"
        Language="{Binding UiCulture, Source={StaticResource Strings}}">
        <!-- A lot more stuff here -->
</Window>

ご覧のとおり、xmlns:hlp="clr-namespace:AC.Frontend.Helper"最初に名前空間を宣言し、その後で binding を宣言していますhlp:AttachedProperties.DialogResult="{Binding DialogResult}"

AttachedProperty見た目はこんな感じ。昨日投稿したものとは異なりますが、私見では何の影響もありません。

public class AttachedProperties
{
    #region DialogResult

    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged));

    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var wnd = d as Window;
        if (wnd == null)
            return;

        wnd.DialogResult = (bool?) e.NewValue;
    }

    public static bool? GetDialogResult(DependencyObject dp)
    {
        if (dp == null) throw new ArgumentNullException("dp");

        return (bool?)dp.GetValue(DialogResultProperty);
    }

    public static void SetDialogResult(DependencyObject dp, object value)
    {
        if (dp == null) throw new ArgumentNullException("dp");

        dp.SetValue(DialogResultProperty, value);
    }

    #endregion
}
于 2013-04-23T15:11:59.967 に答える
13

簡単な方法

public interface IRequireViewIdentification
{
    Guid ViewID { get; }
}

ViewModel への実装

public class MyViewVM : IRequireViewIdentification
{
    private Guid _viewId;

    public Guid ViewID
    {
        get { return _viewId; }
    }

    public MyViewVM()
    {
        _viewId = Guid.NewGuid();
    }
}

一般的なウィンドウ マネージャー ヘルパーを追加します。

public static class WindowManager
{
    public static void CloseWindow(Guid id)
    {
        foreach (Window window in Application.Current.Windows)
        {
            var w_id = window.DataContext as IRequireViewIdentification;
            if (w_id != null && w_id.ViewID.Equals(id))
            {
                window.Close();
            }
        }
    }
}

ビューモデルでこのように閉じます

WindowManager.CloseWindow(ViewID);
于 2014-12-28T13:28:46.863 に答える
4

イベントの代わりに MVVM Light Messenger を使用した簡単な例を次に示します。ビュー モデルは、ボタンがクリックされると閉じるメッセージを送信します。

    public MainViewModel()
    {
        QuitCommand = new RelayCommand(ExecuteQuitCommand);
    }

    public RelayCommand QuitCommand { get; private set; }

    private void ExecuteQuitCommand() 
    {
        Messenger.Default.Send<CloseMessage>(new CloseMessage());
    }

次に、ウィンドウの背後にあるコードで受信されます。

    public Main()
    {   
        InitializeComponent();
        Messenger.Default.Register<CloseMessage>(this, HandleCloseMessage);
    }

    private void HandleCloseMessage(CloseMessage closeMessage)
    {
        Close();
    }
于 2016-09-02T13:05:08.730 に答える
0

これは私がかなり簡単にした方法です:

YourWindow.xaml.cs

//In your constructor
public YourWindow()
{
    InitializeComponent();
    DataContext = new YourWindowViewModel(this);
}

YourWindowViewModel.cs

private YourWindow window;//so we can kill the window

//In your constructor
public YourWindowViewModel(YourWindow window)
{
    this.window = window;
}

//to close the window
public void CloseWindow()
{
    window.Close();
}

あなたが選んだ答えに間違いはありません。これはもっと簡単な方法だと思いました!

于 2014-07-08T21:58:55.770 に答える
0

window をサービス (例: UI サービス) として扱い、それ自体をinterface 経由でviewmodel に渡すことができます。

public interface IMainWindowAccess
{
    void Close(bool result);
}

public class MainWindow : IMainWindowAccess
{
    // (...)
    public void Close(bool result)
    {
        DialogResult = result;
        Close();
    }
}

public class MainWindowViewModel
{
    private IMainWindowAccess access;

    public MainWindowViewModel(IMainWindowAccess access)
    {
        this.access = access;
    }

    public void DoClose()
    {
        access.Close(true);
    }
}

このソリューションには、MVVM を壊すというマイナス面がなくても、ビュー自体を viewmodel に渡すという利点がほとんどあります。これは、物理的にビューが viewmodel に渡されても、後者は前者についてまだ知らないため、一部しか表示されないためIMainWindowAccessです。たとえば、このソリューションを他のプラットフォームに移行したい場合、IMainWindowAccess適切に実装するだけActivityです。

ここにソリューションを投稿して、イベントとは異なるアプローチを提案します (ただし、実際には非常に似ています)。これは、イベントよりも実装 (アタッチ/デタッチなど) が少し簡単に見えるためですが、それでも MVVM パターンとうまく連携します。

于 2019-11-07T08:45:41.727 に答える
-1

次のコードを使用するだけで、現在のウィンドウを閉じることができます。

Application.Current.Windows[0].Close();
于 2014-07-15T06:42:23.680 に答える
-7

System.Environment.Exit(0); ビューモデルで動作します。

于 2014-05-09T08:21:25.363 に答える