web-dev-qa-db-ger.com

Befehl "Fenster schließen" mit MVVM implementieren

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?

35
mcalex

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

29
Rohit Vats

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();
}
56
ken2k

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" />
25
PRASAD CP

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;
12
HB MAAM

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.

10
zmbq

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());
    }
}
5
Krishna

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();
            }
        }
    }
}
5
eoldre

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();
});
3

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());
    }
}
2
Matt Winward

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();
    }
});
2
David Fawzy

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;          
     }      
}
0
dnxit

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();
}
0
Chris Amelinckx

Bitte geben Sie einen Weg an 

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

Kurze Beschreibung

  1. Leiten Sie Ihr ViewModel von INotifyPropertyChanged ab
  2. Erstellen Sie eine beobachtbare Eigenschaft CloseDialog in ViewModel, CloseDialog-Eigenschaft, wenn Sie das Dialogfeld schließen möchten.
  3. Fügen Sie in dieser Ansicht einen Handler für diese Eigenschaftsänderung hinzu
  4. Jetzt bist du fast fertig. Im Event-Handler machen Sie DialogResult = true
0
Anil8753