Zamknij okno z ViewModel

Tworzymy Login używając window control, aby umożliwić użytkownikowi zalogowanie się do aplikacji WPF, którą tworzę.

Do tej pory stworzyłem metodę, która sprawdza, czy użytkownik wprowadził poprawne dane uwierzytelniające dla username i password w textbox na ekranie logowania, binding dwa properties.

Udało mi się to osiągnąć poprzez stworzenie metody bool, jak tak;

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

Mam też command że bind do mojego guzika w xaml Jak więc;

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

Kiedy wpiszę nazwę użytkownika i hasło, wykonuję odpowiedni kod, niezależnie od tego, czy jest dobry, czy zły. Ale jak mogę zamknąć to okno z ViewModel, gdy zarówno nazwa użytkownika, jak i hasło są poprawne?

Próbowałem wcześniej używać dialog modal, ale nie wyszło. Ponadto w mojej aplikacji.xaml, zrobiłem coś takiego jak poniżej, który ładuje najpierw stronę logowania, potem raz true, ładuje rzeczywisty podanie.

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

Pytanie: Jak mogę zamknąć Login Window control z ViewModel?

Z góry dzięki.
 98
Author: Hakan Fıstık, 2013-04-23

17 answers

Możesz przekazać okno do modelu widoku za pomocą CommandParameter. Zobacz mój przykład poniżej.

Zaimplementowałem metodę CloseWindow, która pobiera Windows jako parametr i zamyka go. Okno jest przekazywane do ViewModel poprzez CommandParameter. Zauważ, że musisz zdefiniować x:Name dla okna, które powinno być zamknięte. W moim oknie XAML wywołuję tę metodę poprzez Command i przekazuję samo okno jako parametr do ViewModel za pomocą CommandParameter.

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

ViewModel

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

widok

<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>

Zauważ, że używam frameworka MVVM light, ale zasada dotyczy każdej aplikacji wpf.

To rozwiązanie narusza wzorzec MVVM, ponieważ model widoku nie powinien nic wiedzieć o implementacji interfejsu użytkownika. Jeśli chcesz ściśle przestrzegać paradygmatu programowania MVVM musisz abstrakcyjny typ widoku z interfejsem.

Zgodność z MVVM rozwiązanie (dawny EDIT2)

Użytkownik Crono wymienia ważny punkt w komentarzu:

Przekazanie obiektu Window do modelu widoku powoduje przerwanie wzorca MVVM IMHO, bo zmusza twoją maszynę wirtualną do tego, w czym jest oglądana.

Można to naprawić, wprowadzając interfejs zawierający metodę close.

interfejs:

public interface ICloseable
{
    void Close();
}

Twój refakturowany ViewModel będzie wyglądał jak to:

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

Musisz odwołać się i zaimplementować interfejs ICloseable w swoim widoku

View (Code behind)

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

Odpowiedź na pierwotne pytanie: (były EDIT1)

Twój Przycisk Logowania (Dodany Parametr CommandParameter):

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

Twój kod:

 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();
     }
 }
 161
Author: Joel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-20 12:45:33

Zazwyczaj umieszczam Zdarzenie na modelu widoku, gdy muszę to zrobić, a następnie podłączam je do Window.Close() podczas wiązania modelu widoku z oknem

public class LoginViewModel
{
    public event EventHandler OnRequestClose;

    private void Login()
    {
        // Login logic here
        OnRequestClose(this, new EventArgs());
    }
}

I podczas tworzenia okna logowania

var vm = new LoginViewModel();
var loginWindow = new LoginWindow
{
    DataContext = vm
};
vm.OnRequestClose += (s, e) => loginWindow.Close();

loginWindow.ShowDialog(); 
 38
Author: ChrisO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-23 15:37:54

Pozostając MVVM, myślę, że używając obu zachowań z Blend SDK (System.Okna.Interaktywność) lub niestandardowa Prośba o interakcję z Prism może działać naprawdę dobrze w tego rodzaju sytuacji.

Jeśli chodzi o zachowanie, oto ogólna idea:

public class CloseWindowBehavior : Behavior<Window>
{
    public bool CloseTrigger
    {
        get { return (bool)GetValue(CloseTriggerProperty); }
        set { SetValue(CloseTriggerProperty, value); }
    }

    public static readonly DependencyProperty CloseTriggerProperty =
        DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(CloseWindowBehavior), new PropertyMetadata(false, OnCloseTriggerChanged));

    private static void OnCloseTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = d as CloseWindowBehavior;

        if (behavior != null)
        {
            behavior.OnCloseTriggerChanged();
        }
    }

    private void OnCloseTriggerChanged()
    {
        // when closetrigger is true, close the window
        if (this.CloseTrigger)
        {
            this.AssociatedObject.Close();
        }
    }
}

Następnie w oknie, po prostu powiązać CloseTrigger do wartości logicznej, która byłaby ustawiona, gdy chcesz, aby okno się zamknęło.

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:TestApp"
        Title="MainWindow" Height="350" Width="525">
    <i:Interaction.Behaviors>
        <local:CloseWindowBehavior CloseTrigger="{Binding CloseTrigger}" />
    </i:Interaction.Behaviors>

    <Grid>

    </Grid>
</Window>

Wreszcie, Twój DataContext/ViewModel będzie miał właściwość, którą Ustaw, kiedy chcesz, aby okno się zamknęło w ten sposób:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private bool closeTrigger;

    /// <summary>
    /// Gets or Sets if the main window should be closed
    /// </summary>
    public bool CloseTrigger
    {
        get { return this.closeTrigger; }
        set
        {
            this.closeTrigger = value;
            RaisePropertyChanged(nameof(CloseTrigger));
        }
    }

    public MainWindowViewModel()
    {
        // just setting for example, close the window
        CloseTrigger = true;
    }

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

(Ustaw okno.DataContext = new MainWindowViewModel ())

 36
Author: Steve Van Treeck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-02 18:24:31

Może i jest późno, ale oto moja odpowiedź.]}

foreach (Window item in Application.Current.Windows)
{
    if (item.DataContext == this) item.Close();
}
 23
Author: Ahmed Abuelnour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-30 14:45:13

Oto coś, czego użyłem w kilku projektach. Może to wyglądać jak włamanie, ale działa dobrze.

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

Teraz możesz powiązać DialogResult z maszyną wirtualną i ustawić jej wartość właściwości. Window zamknie się, gdy wartość jest ustawiona.

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

Jest to streszczenie tego, co działa w naszym środowisku produkcyjnym

<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>

Jak widzisz, deklaruję najpierw przestrzeń nazw xmlns:hlp="clr-namespace:AC.Frontend.Helper", a potem Wiązanie hlp:AttachedProperties.DialogResult="{Binding DialogResult}".

AttachedProperty wygląda tak. To nie to samo. napisano wczoraj, ale IMHO nie powinno to mieć żadnego efektu.

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
}
 14
Author: DHN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-03 14:03:58

Easy way

public interface IRequireViewIdentification
{
    Guid ViewID { get; }
}

Zaimplementuj do ViewModel

public class MyViewVM : IRequireViewIdentification
{
    private Guid _viewId;

    public Guid ViewID
    {
        get { return _viewId; }
    }

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

Dodaj General Window manager helper

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

I zamknąć go tak w viewmodel

WindowManager.CloseWindow(ViewID);
 13
Author: RassK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-12 11:56:44

Wiem, że to stary post, prawdopodobnie nikt nie przewija tak daleko, wiem, że nie. więc, po godzinach próbowania różnych rzeczy, znalazłem ten blog i koleś go zabił. Najprostszy sposób, aby to zrobić, próbowałem i działa jak urok.

Blog

W widoku:

...

public bool CanClose { get; set; }

private RelayCommand closeCommand;
public ICommand CloseCommand
{
    get
    {
        if(closeCommand == null)
        (
            closeCommand = new RelayCommand(param => Close(), param => CanClose);
        )
    }
}

public void Close()
{
    this.Close();
}

...

Dodaj właściwość akcji do ViewModel, ale zdefiniuj ją z pliku znajdującego się za kodem widoku. Pozwoli nam to dynamicznie zdefiniować odniesienie do modelu widoku, który wskazuje na widok.

On ViewModel, po prostu dodamy:

public Action CloseAction { get; set; }

I na widoku zdefiniujemy go jako taki:

public View()
{
    InitializeComponent() // this draws the View
    ViewModel vm = new ViewModel(); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if ( vm.CloseAction == null )
        vm.CloseAction = new Action(() => this.Close());
}
 5
Author: Serlok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-25 13:57:29

Oto prosty przykład użycia komunikatora świetlnego MVVM zamiast zdarzenia. Model widoku wysyła komunikat zamknięcia po kliknięciu przycisku:

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

    public RelayCommand QuitCommand { get; private set; }

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

Następnie jest on otrzymywany w kodzie za oknem.

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

    private void HandleCloseMessage(CloseMessage closeMessage)
    {
        Close();
    }
 4
Author: Hamish Gunn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-02 13:05:08

A może to ?

ViewModel:

class ViewModel
{
    public Action CloseAction { get; set; }
    private void Stuff()
    {
       // Do Stuff
       CloseAction(); // closes the window
    }
}

W Twoim ViewModel użyj CloseAction (), aby zamknąć okno tak jak w powyższym przykładzie.

Widok:

public View()
{
    InitializeComponent();
    ViewModel vm = new ViewModel (); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if (vm.CloseAction == null)
        vm.CloseAction = new Action(() => this.Close());
}
 4
Author: Anon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-09 08:39:41

Możesz utworzyć nową obsługę zdarzeń w modelu widoku w ten sposób.

public event EventHandler RequestClose;

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

Następnie zdefiniuj RelayCommand dla ExitCommand.

private RelayCommand _CloseCommand;
    public ICommand CloseCommand
    {
        get
        {
            if(this._CloseCommand==null)
                this._CloseCommand=new RelayCommand(CloseClick);
            return this._CloseCommand;
        }
    }

    private void CloseClick(object obj)
    {
        OnRequestClose();
    }

Następnie w pliku XAML set

<Button Command="{Binding CloseCommand}" />

Ustawia DataContext w xaml.plik cs i zapisz się do wydarzenia, które stworzyliśmy.

public partial class MainWindow : Window
{
    private ViewModel mainViewModel = null;
    public MainWindow()
    {
        InitializeComponent();
        mainViewModel = new ViewModel();
        this.DataContext = mainViewModel;
        mainViewModel.RequestClose += delegate(object sender, EventArgs args) { this.Close(); };
    }
}
 2
Author: Jyotirmaya Prusty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-20 08:52:20

Moim profesjonalnym sposobem jest zadeklarowanie zdarzenia w ViewModel i użycie Blend InvokeMethodAction jak poniżej.

Przykładowy ViewModel

public class MainWindowViewModel : BindableBase, ICloseable
{
    public DelegateCommand SomeCommand { get; private set; }
    #region ICloseable Implementation
    public event EventHandler CloseRequested;        

    public void RaiseCloseNotification()
    {
        var handler = CloseRequested;
        if (handler != null)
        {
            handler.Invoke(this, EventArgs.Empty);
        }
    }
    #endregion

    public MainWindowViewModel()
    {
        SomeCommand = new DelegateCommand(() =>
        {
            //when you decide to close window
            RaiseCloseNotification();
        });
    }
}

I Zamykalny interfejs jest jak poniżej, ale nie wymaga wykonywania tej akcji. ICloseable pomoże w tworzeniu ogólnej usługi widoku, więc jeśli konstruujesz widok i ViewModel przez wstrzyknięcie zależności, to możesz to zrobić

internal interface ICloseable
{
    event EventHandler CloseRequested;
}

Użycie ICloseable

var viewModel = new MainWindowViewModel();
        // As service is generic and don't know whether it can request close event
        var window = new Window() { Content = new MainView() };
        var closeable = viewModel as ICloseable;
        if (closeable != null)
        {
            closeable.CloseRequested += (s, e) => window.Close();
        }

A Poniżej jest Xaml, możesz użyć tego xaml nawet jeśli nie zaimplementujesz interfejsu, to będzie potrzebował tylko modelu widoku, aby podnieść CloseRquested.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFRx"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
xmlns:ViewModels="clr-namespace:WPFRx.ViewModels" x:Name="window" x:Class="WPFRx.MainWindow"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" 
d:DataContext="{d:DesignInstance {x:Type ViewModels:MainWindowViewModel}}">

<i:Interaction.Triggers>
    <i:EventTrigger SourceObject="{Binding Mode=OneWay}" EventName="CloseRequested" >
        <ei:CallMethodAction TargetObject="{Binding ElementName=window}" MethodName="Close"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

<Grid>
    <Button Content="Some Content" Command="{Binding SomeCommand}" Width="100" Height="25"/>
</Grid>

 1
Author: Rajnikant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-06 13:37:09

Możesz użyć {[1] } z zestawu narzędzi MVVMLight. w twoim ViewModel Wyślij taką wiadomość:
Messenger.Default.Send(new NotificationMessage("Close"));
następnie w kodzie windows za, po InitializeComponent, Zarejestruj się dla tej wiadomości w następujący sposób:

Messenger.Default.Register<NotificationMessage>(this, m=>{
    if(m.Notification == "Close") 
    {
        this.Close();
    }
   });

Możesz znaleźć więcej o MVVMLight toolkit tutaj: MVVMLight toolkit on Codeplex

Zauważ, że w MVVM nie ma reguły "no code-behind at all" i możesz zarejestrować wiadomości w widoku code-behind.

 1
Author: Amir Oveisi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-06 17:08:17

To proste. Możesz utworzyć własną klasę ViewModel do logowania-LoginViewModel. Możesz utworzyć widok var dialog = new UserView (); wewnątrz Modela LoginView. I możesz skonfigurować polecenie LoginCommand w przycisku.

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

I

<Button Name="btnCancel" IsDefault="True" Content="Login" Command="{Binding CancelCommand}" />

Klasa ViewModel:

public class LoginViewModel
{
    Window dialog;
    public bool ShowLogin()
    {
       dialog = new UserView();
       dialog.DataContext = this; // set up ViewModel into View
       if (dialog.ShowDialog() == true)
       {
         return true;
       }

       return false;
    }

    ICommand _loginCommand
    public ICommand LoginCommand
    {
        get
        {
            if (_loginCommand == null)
                _loginCommand = new RelayCommand(param => this.Login());

            return _loginCommand;
        }
    }

    public void CloseLoginView()
    {
            if (dialog != null)
          dialog.Close();
    }   

    public void Login()
    {
        if(CheckLogin()==true)
        {
            CloseLoginView();         
        }
        else
        {
          // write error message
        }
    }

    public bool CheckLogin()
    {
      // ... check login code
      return true;
    }
}
 0
Author: misak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-03 08:46:55

W ten sposób zrobiłem to całkiem prosto:

Twój świat.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();
}

Nie widzę nic złego w odpowiedzi, którą wybrałeś, pomyślałem tylko, że to może być prostszy sposób na to!

 0
Author: thestephenstanton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-08 21:58:55

Możesz traktować okno jako usługę (np. UI service) i przekazać się do viewmodel poprzez interfejs , jako takie:

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

To rozwiązanie ma najwięcej plusów z przekazania samego widoku do viewmodel bez konieczności łamania MVVM, ponieważ chociaż fizycznie widok jest przekazywany do viewmodel, ten drugi nadal nie wie o pierwszym, widzi tylko niektóre IMainWindowAccess. Tak więc na przykład, gdybyśmy chcieli przenieść To rozwiązanie na inną platformę, byłoby to tylko kwestią wdrożenia IMainWindowAccess odpowiednio dla, powiedzmy, Activity.

Zamieszczam tutaj rozwiązanie, aby zaproponować inne podejście niż zdarzenia (choć w rzeczywistości jest bardzo podobne), ponieważ wydaje się trochę prostsze niż zdarzenia do wdrożenia (dołączanie/odłączanie itp.), ale nadal ładnie wyrównuje się ze wzorem MVVM.

 0
Author: Spook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-07 08:45:41

Możesz zamknąć bieżące okno za pomocą następującego kodu:

Application.Current.Windows[0].Close();
 -1
Author: chandudab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-15 06:44:21

System.Środowisko.Exit( 0); w widoku będzie działać model.

 -7
Author: rjain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-09 08:21:25