Mein erster Versuch hat also alles hinter dem Code getan, und jetzt versuche ich, meinen Code für die Verwendung des MVVM-Musters umzuwandeln, gemäß den Anweisungen der MVVM in the Box information.
Ich habe eine Ansichtsmodellklasse erstellt, die meiner Ansichtsklasse entspricht, und ich verschiebe den Code aus dem Code dahinter in das Ansichtsmodell, beginnend mit den Befehlen.
Mein erster Haken ist der Versuch, eine Schaltfläche "Schließen" zu implementieren, die das Fenster schließt, wenn die Daten nicht geändert wurden. Ich habe einen CloseCommand aufgebaut, um die "onClick" -Methode zu ersetzen, und alles ist gut, außer wo der Code versucht, this.Close()
auszuführen. Da der Code von einem Fenster in eine normale Klasse verschoben wurde, ist "this" offensichtlich kein Fenster und daher nicht verschließbar. Laut MVVM kennt das Viewmodel die Ansicht jedoch nicht, daher kann ich view.Close()
nicht aufrufen.
Kann jemand vorschlagen, wie ich das Fenster mit dem Befehl viewmodel schließen kann?
Sie müssen die View-Instanz nicht an Ihre ViewModel-Ebene übergeben. Sie können auf das Hauptfenster wie folgt zugreifen -
Application.Current.MainWindow.Close()
Ich sehe kein Problem beim Zugriff auf Ihr Hauptfenster in der ViewModel-Klasse (siehe oben). Nach dem MVVM-Prinzip sollte zwischen Ihrem View und ViewModel keine enge Kopplung bestehen, d. H., Sie sollten die Funktion anderer nicht berücksichtigen. Hier übergeben wir nichts von ViewModel. Wenn Sie nach anderen Optionen suchen möchten, kann dies Ihnen helfen - Fenster mit MVVM schließen
Ich persönlich benutze einen sehr einfachen Ansatz: Für jedes ViewModel, das sich auf eine schließbare View bezieht, habe ich ein Basis-ViewModel wie das folgende Beispiel erstellt:
public abstract class CloseableViewModel
{
public event EventHandler ClosingRequest;
protected void OnClosingRequest()
{
if (this.ClosingRequest != null)
{
this.ClosingRequest(this, EventArgs.Empty);
}
}
}
Rufen Sie dann in Ihrem ViewModel, das von CloseableViewModel
erbt, einfach this.OnClosingRequest();
für den Befehl Close
auf.
In der Ansicht:
public class YourView
{
...
var vm = new ClosableViewModel();
this.Datacontext = vm;
vm.ClosingRequest += (sender, e) => this.Close();
}
Meine Lösung zum Schließen eines Fensters aus dem Ansichtsmodell beim Klicken auf eine Schaltfläche lautet wie folgt:
Im Ansichtsmodell
public RelayCommand CloseWindow;
Constructor()
{
CloseWindow = new RelayCommand(CloseWin);
}
public void CloseWin(object obj)
{
Window win = obj as Window;
win.Close();
}
Stellen Sie in der Ansicht wie folgt ein
<Button Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=WindowNameTobeClose}" Content="Cancel" />
Ich mache es, indem ich eine angehängte Eigenschaft namens DialogResult erstellt:
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);
}
}
dann schreiben Sie diese XAML in das Window-Tag
WindowActions:DialogCloser.DialogResult="{Binding Close}"
endlich im ViewModel
private bool _close;
public bool Close
{
get { return _close; }
set
{
if (_close == value)
return;
_close = value;
NotifyPropertyChanged("Close");
}
}
wenn Sie das Schließen in true ändern, wird das Fenster geschlossen
Close = True;
Achten Sie auf trendige Paradigmen. MVVM kann nützlich sein, aber Sie sollten es nicht als starre Regeln behandeln. Verwenden Sie Ihr eigenes Urteilsvermögen, und wenn es keinen Sinn ergibt - verwenden Sie es nicht.
Die hier angebotenen Lösungen (mit Ausnahme der Lösung von @ RV1987) sind ein sehr gut Beispiel dafür, dass Dinge außer Kontrolle geraten. Sie ersetzen einen einzelnen Close()
-Aufruf durch eine so große Menge Code. Zu welchem Zweck? Sie erhalten absolut nichts, wenn Sie den Abschlusscode von der Ansicht zum Ansichtsmodell verschieben. Das einzige, was Sie gewinnen, ist Platz für weitere Fehler.
Ich sage nicht, dass MVVM ignoriert werden soll. Im Gegenteil, es kann sehr nützlich sein. Mach es einfach nicht vorbei.
Hier ist die einfachste Lösung und reine MVVM-Lösung
ViewModel Code
public class ViewModel
{
public Action CloseAction { get; set; }
private void CloseCommandFunction()
{
CloseAction();
}
}
Hier ist XAML View Code
public partial class DialogWindow : Window
{
public DialogWindow()
{
ViewModel vm = new ViewModel();
this.DataContext = vm;
vm.CloseAction = new Action(() => this.Close());
}
}
Diese Lösung ist schnell und einfach. Nachteil ist, dass zwischen den Schichten eine gewisse Kopplung besteht.
In Ihrem Ansichtsmodell:
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 mit einer benutzerdefinierten Benachrichtigungsbenachrichtigung, um zu vermeiden, dass alle Benachrichtigungsnachrichten verarbeitet werden
Im Ansichtsmodell:
public class CloseDialogMessage : NotificationMessage
{
public CloseDialogMessage(object sender) : base(sender, "") { }
}
private void OnClose()
{
Messenger.Default.Send(new CloseDialogMessage(this));
}
Registrieren Sie die Nachricht im Fenster-Konstruktor:
Messenger.Default.Register<CloseDialogMessage>(this, nm =>
{
Close();
});
Dies ist der Antwort von Eoldre sehr ähnlich. Funktionell ist es das gleiche, dass in derselben Windows-Sammlung nach einem Fenster gesucht wird, in dem das Ansichtsmodell als Datenkontext enthalten ist. Ich habe aber einen RelayCommand und ein paar LINQ verwendet, um das gleiche Ergebnis zu erzielen.
public RelayCommand CloseCommand
{
get
{
return new RelayCommand(() => Application.Current.Windows
.Cast<Window>()
.Single(w => w.DataContext == this)
.Close());
}
}
mit MVVM-Light-Toolkit:
Im ViewModel:
public void notifyWindowToClose()
{
Messenger.Default.Send<NotificationMessage>(
new NotificationMessage(this, "CloseWindowsBoundToMe")
);
}
Und im Blick:
Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
if (nm.Notification == "CloseWindowsBoundToMe")
{
if (nm.Sender == this.DataContext)
this.Close();
}
});
geben Sie Ihrem Fenster zunächst einen Namen wie
x:Name="AboutViewWindow"
auf meinem Schließen-Button habe ich Befehls- und Befehlsparameter wie definiert
CommandParameter="{Binding ElementName=AboutViewWindow}"
Command="{Binding CancelCommand}"
dann aus meiner Sicht Modell
private ICommand _cancelCommand;
public ICommand CancelCommand
{
get
{
if (_cancelCommand == null)
{
_cancelCommand = new DelegateCommand<Window>(
x =>
{
x?.Close();
});
}
return _cancelCommand;
}
}
Dies ist der Antwort von ken2k (Danke!) Zu entnehmen, indem Sie CloseCommand
auch zur Basis CloseableViewModel
hinzufügen.
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;
}
}
Ihr Ansichtsmodell erbt es
public class MyViewModel : CloseableViewModel
Dann auf Sie
public MyView()
{
var viewModel = new StudyDataStructureViewModel(studyId);
this.DataContext = viewModel;
//InitializeComponent(); ...
viewModel.ClosingRequest += (sender, e) => this.Close();
}
Bitte geben Sie einen Weg an
https://stackoverflow.com/a/30546407/3659387
Kurze Beschreibung