web-dev-qa-db-ger.com

WPF MVVM: So schließen Sie ein Fenster

Ich habe ein Button, das 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 hinzufüge, d. H.

<Button x:Name="buttonOk" 
        Command="{Binding SaveCommand}" 
        IsCancel="True">Ok</Button>

Jetzt wird es vermutlich nicht geschlossen, weil ich mit Command arbeite. Ich kann das beheben, indem ich ein EventHandler eingebe und this.Close() aufrufe, d.h.

<Button x:Name="buttonOk" 
        Click="closeWindow" 
        Command="{Binding SaveCommand}" 
        IsCancel="True">Ok</Button>

aber jetzt habe ich Code in meinem Code, d. h. die 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?

64
Bob

Ich habe gerade einen Blog-Beitrag zu diesem Thema abgeschlossen. Kurz gesagt, fügen Sie Ihrem ViewModel eine Action -Eigenschaft mit get und set Accessoren hinzu. Definieren Sie dann den Action aus Ihrem View Konstruktor. Rufen Sie abschließend Ihre Aktion in dem gebundenen Befehl auf, der das Fenster schließen soll.

Im ViewModel:

public Action CloseAction  { get; set;}

und im Konstruktor View:

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 mit 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 Code.

52
Jonathan Shay

Leider ist das Anzeigen von Fenstern in MVVM ein echtes Problem. Daher müssen Sie einige Infrastrukturarbeiten ausführen oder ein MVVM-Framework wie Cinch verwenden. Wenn Sie die Zeit investieren möchten, um es selbst zu tun hier ein Link, wie Cinch es macht.

Es ist gut, dass Sie versuchen, eine Logik aus der Sicht zu halten, aber es ist wirklich nicht das Ende der Welt, wenn Sie dies tun. In diesem Fall hört es sich nicht so an, als würde es zu viele Probleme verursachen.

22
Jon Mitchell

Wie jemand kommentierte, ist der Code, den ich gepostet habe, nicht MVVM-freundlich. Wie wäre es mit der zweiten Lösung?

1. nicht 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: Angehängte Verhaltensweisen verwenden

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

}
15
Simone

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 Window und Button anhängen, um die Arbeit zu 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 hier Command und CommandParameter hinzugefügt, damit Sie einen Befehl ausführen können, bevor Window geschlossen wird.

12

Sehr sauber und MVVM Weg ist es, InteractionTrigger und CallMethodAction zu verwenden, die in Microsoft.Interactivity.Core

Sie müssen wie folgt zwei Namespaces hinzufügen

xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.Microsoft.com/expression/2010/interactions"

Und Assemblies System.Windows.Interactivity und Microsoft.Expression.Interactions und dann Below XAML-Code wird funktionieren.

<Button Content="Save" Command="{Binding SaveCommand}">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
      <ei:CallMethodAction MethodName="Close"
                           TargetObject="{Binding RelativeSource={RelativeSource
                                                  Mode=FindAncestor,
                                                  AncestorType=Window}}" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</Button>

Sie benötigen keinen Code oder irgendetwas anderes und können auch eine andere Methode von Window aufrufen.

10
RAJ

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 gibt es in meiner Lösung einige Einschränkungen. 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 /

7
Ilya Smagin

Ich habe versucht, dieses Problem auf eine allgemeine MVVM-Art zu lösen, stelle jedoch 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 steckt, und ich habe einfach versucht, gute alte Ereignisse in Code dahinter zu verwenden:

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 den Befehlen/MVVM besser unterstützt wird, gibt es meiner Meinung nach keine einfachere und klarere Lösung als die Verwendung von Ereignissen.

5
larsmoa

Ich benutze das Publish Subscribe pattern 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 verwenden, um den MessageBus abzurufen.

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);
    }
}
5
Scott Nimrod

Für diese Aufgabe gibt es ein nützliches Verhalten, das MVVM nicht beeinträchtigt, ein Verhalten, das mit Expression Blend 3 eingeführt wurde, damit sich die Ansicht in Befehle einbinden kann, die vollständig im ViewModel definiert sind.

Dieses Verhalten zeigt eine einfache Technik, mit der ViewModel die Abschlussereignisse der Ansicht in einer Model-View-ViewModel-Anwendung verwalten kann.

Auf diese Weise können Sie ein Verhalten in Ihrer Ansicht (UserControl) verknüpfen, mit dem Sie das Fenster des Steuerelements steuern können. Dadurch kann das ViewModel steuern, ob das Fenster über Standard-ICommands geschlossen werden kann.

Verwenden von Verhalten, um dem ViewModel das Verwalten der Ansichtslebensdauer in M-V-VM zu ermöglichen

http://gallery.expression.Microsoft.com/WindowCloseBehavior/

Der obige Link wurde archiviert zu http://code.msdn.Microsoft.com/Window-Close-Attached-fef26a66#content

3
akjoshi

Wir haben die Namenseigenschaft in der .xaml-Definition:

x:Name="WindowsForm"

Dann haben wir den Button:

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

1
Prabhuprasad NG

Ich musste mich auch mit diesem Problem auseinandersetzen, 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 es das ist, können Sie den Befehl auch in der XAML-Datei binden und das Fenster mit FindAncestor finden und an den Befehlsparameter binden.

0
Hajvaz

Ich denke, der einfachste Weg ist (fast) noch nicht enthalten. Anstatt Verhalten zu verwenden, die neue Abhängigkeiten hinzufügen, verwenden Sie 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 in 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>

Ich habe nach einer Lösung für dasselbe Problem gesucht und festgestellt, dass das Befolgen von Anweisungen problemlos funktioniert. Die Lösung ähnelt dem, was OP in seiner Frage erwähnt hat, mit einigen Unterschieden:

  1. Keine Notwendigkeit für die Eigenschaft IsCancel.

  2. Code dahinter sollte das Fenster nicht schließen. Setze einfach DialogResult

In meinem Fall wird zuerst 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 hinter

private void Apply_OnClick(object sender, RoutedEventArgs e)
{
    this.DialogResult = true;
}

Modell anzeigen

private void Save()
{
 // Save data.
}

Hoffe das hilft.

0
AksharRoop

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

0
ADM-IT

Dies kann hilfreich sein, wenn Sie ein wpf-Fenster mit mvvm mit minimalem Code schließen: http://jkshay.com/closing-a-wpf-window-using-mvvm-and-minimal-code-behind/ =

0
EvilInside

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 tatsächliche Implementierung von Mediator, 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 (ein Token) auslösen

Hören Sie sich diese Benachrichtigung (Token) folgendermaßen im View-Codebehind-Konstruktor an:

public ClientConfigView()
{
    InitializeComponent();
    Mediator.ListenOn(Mediator.Token.ConfigWindowShouldClose, callback => this.Close() );
}
0
imbageek

Die Lösung zum Schließen eines Fensters in wpf, das für mich funktioniert hat, wird hier nicht beantwortet. Deshalb dachte ich, ich würde meine Lösung auch 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" >
0
sheraz yousaf