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