Ich habe eine Button
, die mein Fenster schließt, wenn es angeklickt wird:
<Button x:Name="buttonOk" IsCancel="True">Ok</Button>
Das ist in Ordnung, bis ich ein Command
zum Button
ie hinzufüge
<Button x:Name="buttonOk"
Command="{Binding SaveCommand}"
IsCancel="True">Ok</Button>
Jetzt schließt es vermutlich nicht, weil ich das handhabe Command
. Ich kann dies beheben, indem ich ein EventHandler
Eingabe this.Close()
mache und z
<Button x:Name="buttonOk"
Click="closeWindow"
Command="{Binding SaveCommand}"
IsCancel="True">Ok</Button>
aber jetzt habe ich Code in meinem Code hinter dh der Methode SaveCommand
. Ich verwende das MVVM-Muster und SaveCommand
ist der einzige Code in meinem Code dahinter.
Wie kann ich das anders machen, um keinen Code dahinter zu verwenden?
IsCancel = "True"
einer OK-Taste ist eine schlechte Idee. Diese Eigenschaft gilt für Schaltflächen zum Abbrechen.Antworten:
Ich habe gerade einen Blog-Beitrag zu diesem Thema fertiggestellt. Fügen Sie
Action
Ihrem ViewModel mitget
undset
Accessoren eine Eigenschaft hinzu . Definieren Sie dann dieAction
von IhremView
Konstruktor. Rufen Sie abschließend Ihre Aktion im gebundenen Befehl auf, der das Fenster schließen soll.Im ViewModel:
public Action CloseAction { get; set;}
und im
View
Konstruktor:private View() { InitializeComponent(); ViewModel vm = new ViewModel(); this.DataContext = vm; if ( vm.CloseAction == null ) vm.CloseAction = new Action(this.Close); }
Schließlich können wir in jedem gebundenen Befehl, der das Fenster schließen soll, einfach aufrufen
CloseAction(); // Calls Close() method of the View
Dies funktionierte für mich, schien eine ziemlich elegante Lösung zu sein und ersparte mir eine Menge Codierung.
quelle
this.DataContext = new ViewModel(this.Close);
Anschließend weisen Sie im ViewModel-Konstruktor CloseAction zu. Dies hat auch den Vorteil, dass CloseAction nur verfügbar ist.Sehr sauber und MVVM Weg ist zu verwenden
InteractionTrigger
und zuCallMethodAction
definierenMicrosoft.Interactivity.Core
Sie müssen wie unten einen neuen Namespace hinzufügen
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
Sie benötigen die Assembly Microsoft.Xmal.Behaviours.Wpf, und dann funktioniert der folgende xaml-Code.
<Button Content="Save" Command="{Binding SaveCommand}"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <i:CallMethodAction MethodName="Close" TargetObject="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" /> </i:EventTrigger> </i:Interaction.Triggers> </Button>
Sie brauchen keinen Code dahinter oder irgendetwas anderes und können auch jede andere Methode von aufrufen
Window
.quelle
Wie jemand kommentierte, ist der Code, den ich gepostet habe, nicht MVVM-freundlich. Wie wäre es mit der zweiten Lösung?
1. keine MVVM-Lösung (ich werde dies nicht als Referenz löschen)
XAML:
<Button Name="okButton" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">OK</Button>
ViewModel:
public ICommand OkCommand { get { if (_okCommand == null) { _okCommand = new ActionCommand<Window>(DoOk, CanDoOk); } return _okCommand ; } } void DoOk(Window win) { // Your Code win.DialogResult = true; win.Close(); } bool CanDoOk(Window win) { return true; }
2. wahrscheinlich bessere Lösung: Verwenden von angehängten Verhaltensweisen
XAML
<Button Content="Ok and Close" Command="{Binding OkCommand}" b:CloseOnClickBehaviour.IsEnabled="True" />
Modell anzeigen
public ICommand OkCommand { get { return _okCommand; } }
Verhaltensklasse Ähnliches:
public static class CloseOnClickBehaviour { public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached( "IsEnabled", typeof(bool), typeof(CloseOnClickBehaviour), new PropertyMetadata(false, OnIsEnabledPropertyChanged) ); public static bool GetIsEnabled(DependencyObject obj) { var val = obj.GetValue(IsEnabledProperty); return (bool)val; } public static void SetIsEnabled(DependencyObject obj, bool value) { obj.SetValue(IsEnabledProperty, value); } static void OnIsEnabledPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args) { var button = dpo as Button; if (button == null) return; var oldValue = (bool)args.OldValue; var newValue = (bool)args.NewValue; if (!oldValue && newValue) { button.Click += OnClick; } else if (oldValue && !newValue) { button.PreviewMouseLeftButtonDown -= OnClick; } } static void OnClick(object sender, RoutedEventArgs e) { var button = sender as Button; if (button == null) return; var win = Window.GetWindow(button); if (win == null) return; win.Close(); } }
quelle
Ich persönlich würde ein Verhalten verwenden, um so etwas zu tun:
public class WindowCloseBehaviour : Behavior<Window> { public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command", typeof(ICommand), typeof(WindowCloseBehaviour)); public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register( "CommandParameter", typeof(object), typeof(WindowCloseBehaviour)); public static readonly DependencyProperty CloseButtonProperty = DependencyProperty.Register( "CloseButton", typeof(Button), typeof(WindowCloseBehaviour), new FrameworkPropertyMetadata(null, OnButtonChanged)); public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } public object CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public Button CloseButton { get { return (Button)GetValue(CloseButtonProperty); } set { SetValue(CloseButtonProperty, value); } } private static void OnButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = (Window)((WindowCloseBehaviour)d).AssociatedObject; ((Button) e.NewValue).Click += (s, e1) => { var command = ((WindowCloseBehaviour)d).Command; var commandParameter = ((WindowCloseBehaviour)d).CommandParameter; if (command != null) { command.Execute(commandParameter); } window.Close(); }; } }
Sie können dies dann an Ihre anhängen
Window
undButton
die Arbeit erledigen:<Window x:Class="WpfApplication6.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:WpfApplication6" Title="Window1" Height="300" Width="300"> <i:Interaction.Behaviors> <local:WindowCloseBehaviour CloseButton="{Binding ElementName=closeButton}"/> </i:Interaction.Behaviors> <Grid> <Button Name="closeButton">Close</Button> </Grid> </Window>
Ich habe hinzugefügt
Command
undCommandParameter
hier, damit Sie einen Befehl ausführen können, bevor dasWindow
schließt.quelle
Window.GetWindow(AssociatedObject)?.Close()
(natürlich mit entsprechenden Nullprüfungen), der in Überschreibungen für dieOnAttached
undOnDetaching
-Hooks angehängt / getrennt wird . Drei triviale Funktionen, Null-Eigenschaften und können an eine beliebige Anzahl von Schaltflächen in demselben (oder verschiedenen) Fenstern angehängt werden.Für kleine Apps verwende ich meinen eigenen Application Controller zum Anzeigen, Schließen und Entsorgen von Fenstern und DataContexts. Es ist ein zentraler Punkt in der Benutzeroberfläche einer Anwendung.
Es ist ungefähr so:
//It is singleton, I will just post 2 methods and their invocations public void ShowNewWindow(Window window, object dataContext = null, bool dialog = true) { window.DataContext = dataContext; addToWindowRegistry(dataContext, window); if (dialog) window.ShowDialog(); else window.Show(); } public void CloseWindow(object dataContextSender) { var correspondingWindows = windowRegistry.Where(c => c.DataContext.Equals(dataContextSender)).ToList(); foreach (var pair in correspondingWindows) { pair.Window.Close(); } }
und ihre Aufrufe von ViewModels :
// Show new Window with DataContext ApplicationController.Instance.ShowNewWindow( new ClientCardsWindow(), new ClientCardsVM(), false); // Close Current Window from viewModel ApplicationController.Instance.CloseWindow(this);
Natürlich können Sie einige Einschränkungen in meiner Lösung finden. Nochmals: Ich benutze es für kleine Projekte und es ist genug. Wenn Sie interessiert sind, kann ich den vollständigen Code hier oder woanders posten.
quelle
Ich habe versucht, dieses Problem auf generische MVVM-Weise zu beheben, aber ich stelle immer fest, dass ich am Ende unnötig komplexe Logik habe. Um ein enges Verhalten zu erreichen, habe ich eine Ausnahme von der Regel gemacht, dass kein Code dahinter steht, und einfach gute alte Ereignisse im Code dahinter verwendet:
XAML:
<Button Content="Close" Click="OnCloseClicked" />
Code dahinter:
private void OnCloseClicked(object sender, EventArgs e) { Visibility = Visibility.Collapsed; }
Obwohl ich mir wünsche, dass dies mit Befehlen / MVVM besser unterstützt wird, denke ich einfach, dass es keine einfachere und klarere Lösung als die Verwendung von Ereignissen gibt.
quelle
Ich verwende das Publish Subscribe-Muster für komplizierte Klassenabhängigkeiten:
ViewModel:
public class ViewModel : ViewModelBase { public ViewModel() { CloseComand = new DelegateCommand((obj) => { MessageBus.Instance.Publish(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, null); }); } }
Fenster:
public partial class SomeWindow : Window { Subscription _subscription = new Subscription(); public SomeWindow() { InitializeComponent(); _subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj => { this.Close(); }); } }
Sie können Bizmonger.Patterns nutzen , um den MessageBus .
MessageBus
public class MessageBus { #region Singleton static MessageBus _messageBus = null; private MessageBus() { } public static MessageBus Instance { get { if (_messageBus == null) { _messageBus = new MessageBus(); } return _messageBus; } } #endregion #region Members List<Observer> _observers = new List<Observer>(); List<Observer> _oneTimeObservers = new List<Observer>(); List<Observer> _waitingSubscribers = new List<Observer>(); List<Observer> _waitingUnsubscribers = new List<Observer>(); int _publishingCount = 0; #endregion public void Subscribe(string message, Action<object> response) { Subscribe(message, response, _observers); } public void SubscribeFirstPublication(string message, Action<object> response) { Subscribe(message, response, _oneTimeObservers); } public int Unsubscribe(string message, Action<object> response) { var observers = new List<Observer>(_observers.Where(o => o.Respond == response).ToList()); observers.AddRange(_waitingSubscribers.Where(o => o.Respond == response)); observers.AddRange(_oneTimeObservers.Where(o => o.Respond == response)); if (_publishingCount == 0) { observers.ForEach(o => _observers.Remove(o)); } else { _waitingUnsubscribers.AddRange(observers); } return observers.Count; } public int Unsubscribe(string subscription) { var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription).ToList()); observers.AddRange(_waitingSubscribers.Where(o => o.Subscription == subscription)); observers.AddRange(_oneTimeObservers.Where(o => o.Subscription == subscription)); if (_publishingCount == 0) { observers.ForEach(o => _observers.Remove(o)); } else { _waitingUnsubscribers.AddRange(observers); } return observers.Count; } public void Publish(string message, object payload) { _publishingCount++; Publish(_observers, message, payload); Publish(_oneTimeObservers, message, payload); Publish(_waitingSubscribers, message, payload); _oneTimeObservers.RemoveAll(o => o.Subscription == message); _waitingUnsubscribers.Clear(); _publishingCount--; } private void Publish(List<Observer> observers, string message, object payload) { Debug.Assert(_publishingCount >= 0); var subscribers = observers.Where(o => o.Subscription.ToLower() == message.ToLower()); foreach (var subscriber in subscribers) { subscriber.Respond(payload); } } public IEnumerable<Observer> GetObservers(string subscription) { var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription)); return observers; } public void Clear() { _observers.Clear(); _oneTimeObservers.Clear(); } #region Helpers private void Subscribe(string message, Action<object> response, List<Observer> observers) { Debug.Assert(_publishingCount >= 0); var observer = new Observer() { Subscription = message, Respond = response }; if (_publishingCount == 0) { observers.Add(observer); } else { _waitingSubscribers.Add(observer); } } #endregion }
}}
Abonnement
public class Subscription { #region Members List<Observer> _observerList = new List<Observer>(); #endregion public void Unsubscribe(string subscription) { var observers = _observerList.Where(o => o.Subscription == subscription); foreach (var observer in observers) { MessageBus.Instance.Unsubscribe(observer.Subscription, observer.Respond); } _observerList.Where(o => o.Subscription == subscription).ToList().ForEach(o => _observerList.Remove(o)); } public void Subscribe(string subscription, Action<object> response) { MessageBus.Instance.Subscribe(subscription, response); _observerList.Add(new Observer() { Subscription = subscription, Respond = response }); } public void SubscribeFirstPublication(string subscription, Action<object> response) { MessageBus.Instance.SubscribeFirstPublication(subscription, response); } }
quelle
Für diese Aufgabe gibt es ein nützliches Verhalten, das MVVM nicht unterbricht. Dieses Verhalten wurde mit Expression Blend 3 eingeführt, damit sich die Ansicht in Befehle einbinden kann, die vollständig im ViewModel definiert sind.
Der obige Link wurde unter http://code.msdn.microsoft.com/Window-Close-Attached-fef26a66#content archiviert
quelle
Ich hatte einige Zeit mit diesem Thema zu kämpfen und entschied mich schließlich für den einfachsten Ansatz, der immer noch mit MVVM vereinbar ist: Lassen Sie die Schaltfläche den Befehl ausführen, der das ganze schwere Heben ausführt, und lassen Sie den Click-Handler der Schaltfläche das Fenster schließen.
XAML
<Button x:Name="buttonOk" Click="closeWindow" Command="{Binding SaveCommand}" />
XAML.cs
public void closeWindow() { this.DialogResult = true; }
SaveCommand.cs
// I'm in my own file, not the code-behind!
Es stimmt, es gibt immer noch Code-Behind, aber daran ist nichts von Natur aus schlecht. Und aus OO-Sicht ist es für mich am sinnvollsten, dem Fenster nur zu sagen, dass es sich selbst schließen soll.
quelle
Wir haben die Eigenschaft name in der .xaml-Definition:
x:Name="WindowsForm"
Dann haben wir den Knopf:
<Button Command="{Binding CloseCommand}" CommandParameter="{Binding ElementName=WindowsForm}" />
Dann im ViewModel:
public DelegateCommand <Object> CloseCommand { get; private set; } Constructor for that view model: this.CloseCommand = new DelegateCommand<object>(this.CloseAction);
Dann endlich die Aktionsmethode:
private void CloseAction (object obj) { Window Win = obj as Window; Win.Close(); }
Ich habe diesen Code verwendet, um ein Popup-Fenster aus einer Anwendung zu schließen.
quelle
Ich musste dies in einer WPF-Anwendung tun, die auf .Net Core 3.0 basiert, wo leider keine Verhaltensunterstützung im Microsoft.Xaml.Behaviors.Wpf NuGet-Paket offiziell verfügbar war .
Stattdessen habe ich mich für eine Lösung entschieden, bei der das Fassadenmuster verwendet wurde.
Schnittstelle:
public interface IWindowFacade { void Close(); }
Fenster:
public partial class MainWindow : Window, IWindowFacade …
Standardbefehlseigenschaft für das Ansichtsmodell:
public ICommand ExitCommand …
Kontrollbindung:
<MenuItem Header="E_xit" Command="{Binding ExitCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
Befehl:
public class ExitCommand : ICommand { … public void Execute(object parameter) { var windowFacade = parameter as IWindowFacade; windowFacade?.Close(); } … }
Da die
Close()
Methode bereits von derWindow
Klasse implementiert wurde , ist das Anwenden der Fassadenschnittstelle auf das Fenster der einzige erforderliche Code in der UI-Ebene (für dieses einfache Beispiel). Der Befehl in der Präsentationsebene vermeidet Abhängigkeiten von der Ansichts- / Benutzeroberflächenebene, da er keine Ahnung hat, womit er spricht, wenn er dieClose
Methode an der Fassade aufruft .quelle
xaml.cs
Rufen Sie in Ihrer aktuellen Fensterdatei den folgenden Code auf:var curWnd = Window.GetWindow(this); // passing current window context curWnd?.Close();
Das sollte das Ding machen.
Es hat bei mir funktioniert, ich hoffe, dass es Ihnen auch so geht.
quelle
Ich habe folgende Lösung in Silverlight. Wäre auch in WPF.
ChildWindowExt.cs:
namespace System.Windows.Controls { public class ChildWindowExt : ChildWindow { public static readonly DependencyProperty IsOpenedProperty = DependencyProperty.Register( "IsOpened", typeof(bool), typeof(ChildWindowExt), new PropertyMetadata(false, IsOpenedChanged)); private static void IsOpenedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if ((bool)e.NewValue == false) { ChildWindowExt window = d as ChildWindowExt; window.Close(); } else if ((bool)e.NewValue == true) { ChildWindowExt window = d as ChildWindowExt; window.Show(); } } public bool IsOpened { get { return (bool)GetValue(IsOpenedProperty); } set { SetValue(IsOpenedProperty, value); } } protected override void OnClosing(ComponentModel.CancelEventArgs e) { this.IsOpened = false; base.OnClosing(e); } protected override void OnOpened() { this.IsOpened = true; base.OnOpened(); } } }
ItemWindow.xaml:
<extControls:ChildWindowExt x:Class="MyProject.ItemWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:extControls="clr-namespace:System.Windows.Controls" Title="{Binding Title}" IsOpened="{Binding IsOpened, Mode=TwoWay}" Width="640" Height="480"> <Grid x:Name="LayoutRoot"> <Button Command="{Binding UpdateCommand}" Content="OK" Width="70" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </extControls:ChildWindowExt>
ItemViewModel.cs:
private bool _IsOpened; public bool IsOpened { get { return _IsOpened; } set { if (!Equals(_IsOpened, value)) { _IsOpened = value; RaisePropertyChanged("IsOpened"); } } } private RelayCommand _UpdateCommand; /// <summary> /// Insert / Update data entity /// </summary> public RelayCommand UpdateCommand { get { if (_UpdateCommand == null) { _UpdateCommand = new RelayCommand( () => { // Insert / Update data entity ... IsOpened = false; }, () => { return true; }); } return _UpdateCommand; } }
ItemsViewModel.cs:
private RelayCommand _InsertItemCommand; /// <summary> /// /// </summary> public RelayCommand InsertItemCommand { get { if (_InsertItemCommand == null) { _InsertItemCommand = new RelayCommand( () => { ItemWindow itemWin = new ItemWindow(); itemWin.DataContext = new ItemViewModel(); itemWin.Show(); // OR // ItemWindow itemWin = new ItemWindow(); // ItemViewModel newItem = new ItemViewModel(); // itemWin.DataContext = newItem; // newItem.IsOpened = true; }, () => { return true; }); } return _InsertItemCommand; } }
MainPage.xaml:
<Grid x:Name="LayoutRoot"> <Button Command="{Binding InsertItemCommand}" Content="Add New" Width="70" HorizontalAlignment="Left" VerticalAlignment="Center" /> </Grid>
Ich wünsche euch allen gute Ideen und Projekte ;-)
quelle
Dies kann Ihnen helfen, ein wpf-Fenster mit mvvm mit minimalem Code zu schließen: http://jkshay.com/closing-a-wpf-window-using-mvvm-and-minimal-code-behind/
quelle
Ich denke, der einfachste Weg wurde noch nicht (fast) aufgenommen. Verwenden Sie anstelle von Behaviors, das neue Abhängigkeiten hinzufügt, einfach angehängte Eigenschaften:
using System; using System.Windows; using System.Windows.Controls; public class DialogButtonManager { public static readonly DependencyProperty IsAcceptButtonProperty = DependencyProperty.RegisterAttached("IsAcceptButton", typeof(bool), typeof(DialogButtonManager), new FrameworkPropertyMetadata(OnIsAcceptButtonPropertyChanged)); public static readonly DependencyProperty IsCancelButtonProperty = DependencyProperty.RegisterAttached("IsCancelButton", typeof(bool), typeof(DialogButtonManager), new FrameworkPropertyMetadata(OnIsCancelButtonPropertyChanged)); public static void SetIsAcceptButton(UIElement element, bool value) { element.SetValue(IsAcceptButtonProperty, value); } public static bool GetIsAcceptButton(UIElement element) { return (bool)element.GetValue(IsAcceptButtonProperty); } public static void SetIsCancelButton(UIElement element, bool value) { element.SetValue(IsCancelButtonProperty, value); } public static bool GetIsCancelButton(UIElement element) { return (bool)element.GetValue(IsCancelButtonProperty); } private static void OnIsAcceptButtonPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { Button button = sender as Button; if (button != null) { if ((bool)e.NewValue) { SetAcceptButton(button); } else { ResetAcceptButton(button); } } } private static void OnIsCancelButtonPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { Button button = sender as Button; if (button != null) { if ((bool)e.NewValue) { SetCancelButton(button); } else { ResetCancelButton(button); } } } private static void SetAcceptButton(Button button) { Window window = Window.GetWindow(button); button.Command = new RelayCommand(new Action<object>(ExecuteAccept)); button.CommandParameter = window; } private static void ResetAcceptButton(Button button) { button.Command = null; button.CommandParameter = null; } private static void ExecuteAccept(object buttonWindow) { Window window = (Window)buttonWindow; window.DialogResult = true; } private static void SetCancelButton(Button button) { Window window = Window.GetWindow(button); button.Command = new RelayCommand(new Action<object>(ExecuteCancel)); button.CommandParameter = window; } private static void ResetCancelButton(Button button) { button.Command = null; button.CommandParameter = null; } private static void ExecuteCancel(object buttonWindow) { Window window = (Window)buttonWindow; window.DialogResult = false; } }
Dann stellen Sie es einfach auf Ihren Dialogschaltflächen ein:
<UniformGrid Grid.Row="2" Grid.Column="1" Rows="1" Columns="2" Margin="3" > <Button Content="Accept" IsDefault="True" Padding="3" Margin="3,0,3,0" DialogButtonManager.IsAcceptButton="True" /> <Button Content="Cancel" IsCancel="True" Padding="3" Margin="3,0,3,0" DialogButtonManager.IsCancelButton="True" /> </UniformGrid>
quelle
Ich musste mich auch mit diesem Problem befassen, also hier meine Lösung. Es funktioniert großartig für mich.
1. Erstellen Sie die Klasse DelegateCommand
public class DelegateCommand<T> : ICommand { private Predicate<T> _canExecuteMethod; private readonly Action<T> _executeMethod; public event EventHandler CanExecuteChanged; public DelegateCommand(Action<T> executeMethod) : this(executeMethod, null) { } public DelegateCommand(Action<T> executeMethod, Predicate<T> canExecuteMethod) { this._canExecuteMethod = canExecuteMethod; this._executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod), "Command is not specified."); } public void RaiseCanExecuteChanged() { if (this.CanExecuteChanged != null) CanExecuteChanged(this, null); } public bool CanExecute(object parameter) { return _canExecuteMethod == null || _canExecuteMethod((T)parameter) == true; } public void Execute(object parameter) { _executeMethod((T)parameter); } }
2. Definieren Sie Ihren Befehl
public DelegateCommand<Window> CloseWindowCommand { get; private set; } public MyViewModel()//ctor of your viewmodel { //do something CloseWindowCommand = new DelegateCommand<Window>(CloseWindow); } public void CloseWindow(Window win) // this method is also in your viewmodel { //do something win?.Close(); }
3. Binden Sie Ihren Befehl in die Ansicht
public MyView(Window win) //ctor of your view, window as parameter { InitializeComponent(); MyButton.CommandParameter = win; MyButton.Command = ((MyViewModel)this.DataContext).CloseWindowCommand; }
4. Und jetzt das Fenster
Window win = new Window() { Title = "My Window", Height = 800, Width = 800, WindowStartupLocation = WindowStartupLocation.CenterScreen, }; win.Content = new MyView(win); win.ShowDialog();
Damit können Sie den Befehl auch in der xaml-Datei binden, das Fenster mit FindAncestor suchen und an den Befehlsparameter binden.
quelle
Ich habe nach einer Lösung für das gleiche Problem gesucht und festgestellt, dass das Folgende gut funktioniert. Die Lösung ähnelt der von OP in seiner Frage erwähnten mit einigen Unterschieden:
Keine Notwendigkeit von
IsCancel
Eigentum.Der Code dahinter sollte das Fenster nicht schließen. Einfach einstellen
DialogResult
In meinem Fall wird zuerst der Code dahinter ausgeführt und dann der an die Schaltfläche gebundene Modellbefehl angezeigt.
XAML
<Button x:Name="buttonOk" Click="Save_Click" Command="{Binding SaveCommand}">OK</Button>
Code dahinter
private void Apply_OnClick(object sender, RoutedEventArgs e) { this.DialogResult = true; }
Modell anzeigen
private void Save() { // Save data. }
Hoffe das hilft.
quelle
Sie könnten die Frage umformulieren und auf diese Weise eine andere Lösung finden. Wie kann ich die Kommunikation zwischen Ansichten, Ansichtsmodellen und so weiter in einer MVVM-Umgebung aktivieren? Sie können das Mediator-Muster verwenden. Es ist im Grunde ein Benachrichtigungssystem. Für die eigentliche Mediator-Implementierung googeln Sie danach oder fragen Sie mich, und ich kann es per E-Mail senden.
Erstellen Sie einen Befehl, mit dem die Ansicht geschlossen werden soll.
public void Execute( object parameter ) { this.viewModel.DisposeMyStuff(); Mediator.NotifyColleagues(Mediator.Token.ConfigWindowShouldClose); }
Der Mediator wird eine Benachrichtigung auslösen (ein Token)
Hören Sie sich diese Benachrichtigung (Token) wie folgt im View codebehind-Konstruktor an:
public ClientConfigView() { InitializeComponent(); Mediator.ListenOn(Mediator.Token.ConfigWindowShouldClose, callback => this.Close() ); }
quelle
Die Lösung zum Schließen eines Fensters in wpf, die für mich funktioniert hat, wird hier nicht beantwortet, daher dachte ich, ich würde auch meine Lösung hinzufügen.
private static Window GetWindow(DependencyObject sender) { Window window = null; if (sender is Window) window = (Window)sender; if (window == null) window = Window.GetWindow(sender); return window; } private void CloseWindow(object sender, RoutedEventArgs e) { var button = (Button)sender as DependencyObject; Window window = GetWindow(button); if (window != null) window.Close(); // window.Visibility = Visibility.Hidden; // choose between window.close or set window.visibility to close or hide the window. // } }
Fügen Sie der Schaltfläche in Ihrem Fenster das CloseWindow-Ereignis wie folgt hinzu.
<Button Content="Cancel" Click="CloseWindow" >
quelle
Ein einfacher Ansatz ist das Schließen des Fensters bei der Implementierung von saveComand. Verwenden Sie den folgenden Code, um das Fenster zu schließen.
Application.Current.Windows[1].Close();
Das untergeordnete Fenster wird geschlossen.
quelle
Sie können es ohne Code dahinter tun. Erstellen Sie einen Befehl, und rufen Sie in Execute method die Methode "Save" im Ansichtsmodell und anschließend die Methode close im Bearbeitungsfenster auf, die Sie über den Parameter an den Befehl übergeben können:
public void Execute(object parameter) { _mainViewModel.SaveSomething(); var editWindow = parameter as MyEditWindow; editWindow?.Close(); }
Schaltfläche Speichern & Schließen XAML:
<Button Content"Save&Close" Command="{Binding SaveCmd}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" IsDefault="True" />
quelle