44

そのため、最初の試みはコードビハインドからすべてを実行し、現在はボックス情報のMVVMのガイダンスに従って、MVVMパターンを使用するようにコードをリファクタリングしようとしています。

ビュークラスに一致するビューモデルクラスを作成し、コマンドから始めて、コードをコードビハインドからビューモデルに移動しています。

私の最初の問題は、データが変更されていない場合にウィンドウを閉じる「閉じる」ボタンを実装しようとしています。CloseCommandを装備して、「onClick」メソッドを置き換えました。コードを実行しようとする場所を除いて、すべて問題ありませんthis.Close()。明らかに、コードがウィンドウから通常のクラスに移動されたため、「this」はウィンドウではなく、したがって閉じることができません。ただし、MVVMによると、ビューモデルはビューを認識していないため、を呼び出すことはできませんview.Close()

誰かがviewmodelコマンドからウィンドウを閉じる方法を提案できますか?

4

12 に答える 12

67

私は個人的に非常に単純なアプローチを使用しています。閉じ可能なビューに関連するすべてのViewModelに対して、次の例のようなベースViewModelを作成しました。

public abstract class CloseableViewModel
{
    public event EventHandler ClosingRequest;

    protected void OnClosingRequest()
    {
        if (this.ClosingRequest != null)
        {
            this.ClosingRequest(this, EventArgs.Empty);
        }
    }
}

次に、から継承するViewModelで、コマンドCloseableViewModelを呼び出すだけです。this.OnClosingRequest();Close

ビューで:

public class YourView
{
    ...
    var vm = new ClosableViewModel();
    this.Datacontext = vm;
    vm.ClosingRequest += (sender, e) => this.Close();
}
于 2012-08-14T08:31:42.133 に答える
29

ViewインスタンスをViewModelレイヤーに渡す必要はありません。このようにメインウィンドウにアクセスできます-

Application.Current.MainWindow.Close()

上記のように、ViewModelクラスのメインウィンドウにアクセスしても問題はありません。MVVMの原則に従って、ViewとViewModelの間に緊密な結合があってはなりません。つまり、他の操作を気にせずに機能する必要があります。ここでは、ViewからViewModelに何も渡していません。他のオプションを探したい場合は、これが役立つ可能性があります-MVVMを使用してウィンドウを閉じます

于 2012-08-14T08:09:23.777 に答える
27

ボタンをクリックしながらビューモデルからウィンドウを閉じるための私の解決策は次のとおりです。

ビューモデル

public RelayCommand CloseWindow;
Constructor()
{
    CloseWindow = new RelayCommand(CloseWin);
}

public void CloseWin(object obj)
{
    Window win = obj as Window;
    win.Close();
}

ビューで、次のように設定します

<Button Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=WindowNameTobeClose}" Content="Cancel" />
于 2013-08-29T06:33:00.817 に答える
13

私はDialogResultと呼ばれる添付プロパティを作成することによってそれを行います:

public static class DialogCloser
{
    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached(
            "DialogResult",
            typeof(bool?),
            typeof(DialogCloser),
            new PropertyMetadata(DialogResultChanged));

    private static void DialogResultChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window != null && (bool?)e.NewValue == true) 
                window.Close();
    }

    public static void SetDialogResult(Window target, bool? value)
    {
        target.SetValue(DialogResultProperty, value);
    }
}

次に、これをウィンドウタグでXAMLに書き込みます

WindowActions:DialogCloser.DialogResult="{Binding Close}"

最後にViewModelで

    private bool _close;
    public bool Close
    {
        get { return _close; }
        set
        {
            if (_close == value)
                return;
            _close = value;
            NotifyPropertyChanged("Close");
        }
    }

Closeをtrueに変更すると、ウィンドウが閉じます

Close = True;
于 2012-08-14T07:16:18.610 に答える
6

これが最もシンプルで純粋なMVVMソリューションです

ViewModelコード

public class ViewModel
{
    public Action CloseAction { get; set; }

    private void CloseCommandFunction()
    {
        CloseAction();
    }
}

これがXAMLビューコードです

public partial class DialogWindow : Window
{
    public DialogWindow()
    {
        ViewModel vm = new ViewModel();
        this.DataContext = vm;

        vm.CloseAction = new Action(() => this.Close());
    }
}
于 2017-09-07T12:56:06.940 に答える
5

このソリューションは迅速かつ簡単です。欠点は、レイヤー間にいくつかの結合があることです。

ビューモデルの場合:

public class MyWindowViewModel: ViewModelBase
{


    public Command.StandardCommand CloseCommand
    {
        get
        {
            return new Command.StandardCommand(Close);
        }
    }
    public void Close()
    {
        foreach (System.Windows.Window window in System.Windows.Application.Current.Windows)
        {
            if (window.DataContext == this)
            {
                window.Close();
            }
        }
    }
}
于 2013-10-02T13:48:34.017 に答える
4

MVVM-すべての通知メッセージを処理するウィンドウを回避するためのカスタムメッセージ通知を備えたライト

ビューモデルの場合:

public class CloseDialogMessage : NotificationMessage
{
    public CloseDialogMessage(object sender) : base(sender, "") { }
}

private void OnClose()
{
    Messenger.Default.Send(new CloseDialogMessage(this));
}

メッセージをウィンドウコンストラクタに登録します。

Messenger.Default.Register<CloseDialogMessage>(this, nm =>
{
    Close();
});
于 2017-01-21T07:33:20.320 に答える
2

これは、eoldreの答えと非常によく似ています。データコンテキストとしてビューモデルを持つウィンドウを同じWindowsコレクションで検索するという点で、機能的には同じです。しかし、同じ結果を達成するために、RelayCommandといくつかのLINQを使用しました。

public RelayCommand CloseCommand
{
    get
    {
        return new RelayCommand(() => Application.Current.Windows
            .Cast<Window>()
            .Single(w => w.DataContext == this)
            .Close());
    }
}
于 2014-06-03T21:06:20.883 に答える
2

MVVM-lightツールキットの使用:

ViewModelの場合:

 public void notifyWindowToClose()
{
    Messenger.Default.Send<NotificationMessage>(
        new NotificationMessage(this, "CloseWindowsBoundToMe")
    );
}

そして、ビューで:

 Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
    if (nm.Notification == "CloseWindowsBoundToMe")
    {
        if (nm.Sender == this.DataContext)
            this.Close();
    }
});
于 2016-07-19T10:15:16.397 に答える
0

これはken2kの回答(ありがとう!)から取得CloseCommandしたもので、ベースにも追加するだけCloseableViewModelです。

public class CloseableViewModel
{
    public CloseableViewModel()
    {
        CloseCommand = new RelayCommand(this.OnClosingRequest);
    }

    public event EventHandler ClosingRequest;

    protected void OnClosingRequest()
    {
        if (this.ClosingRequest != null)
        {
            this.ClosingRequest(this, EventArgs.Empty);
        }
    }

    public RelayCommand CloseCommand
    {
        get;
        private set;
    }
}

あなたのビューモデルはそれを継承します

public class MyViewModel : CloseableViewModel

次に、あなたが見る

public MyView()
{
    var viewModel = new StudyDataStructureViewModel(studyId);
    this.DataContext = viewModel;

    //InitializeComponent(); ...

    viewModel.ClosingRequest += (sender, e) => this.Close();
}
于 2014-08-27T20:32:20.157 に答える
0

方法を考えて、確認してください

https://stackoverflow.com/a/30546407/3659387

簡単な説明

  1. INotifyPropertyChangedからViewModelを取得します
  2. ViewModelで監視可能なプロパティCloseDialogを作成し、ダイアログを閉じたいときはいつでもCloseDialogプロパティを変更します。
  3. このプロパティの変更のためにビューにハンドラーをアタッチします
  4. これでほぼ完了です。イベントハンドラーでDialogResult=trueを作成します
于 2015-05-30T13:10:31.800 に答える
0

まず、ウィンドウに次のような名前を付けます

x:Name="AboutViewWindow"

閉じるボタンで、コマンドとコマンドパラメータを次のように定義しました

CommandParameter="{Binding ElementName=AboutViewWindow}"
Command="{Binding CancelCommand}"

それから私のビューモデルで

private ICommand _cancelCommand;        
public ICommand CancelCommand       
{
   get          
     {
        if (_cancelCommand == null)
           {
              _cancelCommand = new DelegateCommand<Window>(
                    x =>
                    {
                        x?.Close();
                    });
            }

            return _cancelCommand;          
     }      
}
于 2017-10-12T20:28:19.890 に答える