だから、私の最初の試みはコードビハインドからすべてを行ったので、MVVM in the box 情報のガイダンスに従って、MVVMパターンを使用するようにコードをリファクタリングしようとしています。
ビュークラスに合わせてビューモデルクラスを作成し、コマンドから始めて、コードをコードからビューモデルに移動しています。
私の最初の障害は、データが変更されていない場合にウィンドウを閉じる「閉じる」ボタンを実装しようとしています。 'onClick'メソッドを置き換えるためにCloseCommandを作成しましたが、コードがthis.Close()
を実行しようとする場所を除いてすべてが適切です。明らかに、コードはウィンドウから通常のクラスに移動されているため、「this」はウィンドウではないため、閉じることができません。ただし、MVVMによると、ビューモデルはビューについて知らないため、view.Close()
を呼び出すことができません。
誰かがviewmodelコマンドからウィンドウを閉じる方法を提案できますか?
ViewインスタンスをViewModelレイヤーに渡す必要はありません。このようにメインウィンドウにアクセスできます-
Application.Current.MainWindow.Close()
上記のように、ViewModelクラスのメインウィンドウにアクセスしても問題はありません。 MVVMの原則に従って、ViewとViewModelの間の密結合はないはずです。つまり、他の操作を無視して動作するはずです。ここでは、ViewからViewModelに何も渡していません。他のオプションを探したい場合は、これが役立つかもしれません- MVVMを使用してウィンドウを閉じる
私は個人的に非常に単純なアプローチを使用しています。閉じることができるビューに関連するすべてのViewModelについて、次の例のようなベースViewModelを作成しました。
_public abstract class CloseableViewModel
{
public event EventHandler ClosingRequest;
protected void OnClosingRequest()
{
if (this.ClosingRequest != null)
{
this.ClosingRequest(this, EventArgs.Empty);
}
}
}
_
次に、CloseableViewModel
から継承するViewModelで、Close
コマンドに対してthis.OnClosingRequest();
を呼び出すだけです。
ビューで:
_public class YourView
{
...
var vm = new ClosableViewModel();
this.Datacontext = vm;
vm.ClosingRequest += (sender, e) => this.Close();
}
_
ボタンをクリックしながらビューモデルからウィンドウを閉じる私のソリューションは次のとおりです。
ビューモデル
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" />
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);
}
}
次に、windowタグでこれを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;
トレンディなパラダイムに注意してください。 MVVMは便利ですが、厳密なルールのセットとして扱うべきではありません。独自の判断を使用し、それが意味をなさない場合-それを使用しないでください。
ここで提供されるソリューション(@ RV1987のソリューションを除く)は、手に負えない事態の例非常に良いです。単一のClose()
呼び出しをこのような膨大な量のコードに置き換えているのは、どのような目的ですか?閉じているコードをビューからビューモデルに移動しても何も得られません。あなたが得る唯一のものは、より多くのバグの余地です。
今、私はMVVMが無視されると言っているわけではありません。それどころか、非常に便利です。やりすぎないでください。
これが最もシンプルで純粋な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());
}
}
このソリューションは迅速かつ簡単です。欠点は、レイヤー間にいくつかのカップリングがあることです。
ビューモデルで:
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();
}
}
}
}
すべての通知メッセージを処理するウィンドウを回避するためのカスタムメッセージ通知を備えたMVVM-light
ビューモデルで:
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();
});
これはeoldreの答えに非常に似ています。機能的には、データコンテキストとしてビューモデルを持つウィンドウの同じWindowsコレクションを検索するという点で同じです。しかし、同じ結果を得るために、RelayCommandといくつかのLINQを使用しました。
public RelayCommand CloseCommand
{
get
{
return new RelayCommand(() => Application.Current.Windows
.Cast<Window>()
.Single(w => w.DataContext == this)
.Close());
}
}
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();
}
});
まず、ウィンドウに次のような名前を付けます
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;
}
}
これは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();
}
方法を考えて、確認してください
https://stackoverflow.com/a/30546407/3659387
簡単な説明