Подтвердить что ты не робот

Выполнение команды "закрыть окно" с MVVM

Итак, моя первая попытка сделала все из кода позади, и теперь я пытаюсь реорганизовать мой код, чтобы использовать шаблон MVVM, следуя указаниям MVVM в информации о коробке.

Я создал класс viewmodel для соответствия моему классу представления, и я перемещаю код из кода в viewmodel, начиная с команд.

Моя первая проблема - реализовать кнопку "Закрыть", которая закрывает окно, если данные не были изменены. Я установил CloseCommand для замены метода 'onClick', и все хорошо, за исключением тех случаев, когда код пытается выполнить this.Close(). Очевидно, что поскольку код был перемещен из окна в обычный класс, "this" не является окном и поэтому не может быть закрыто. Однако, согласно MVVM, модель представления не знает о представлении, поэтому я не могу вызвать view.Close().

Может кто-нибудь подсказать, как можно закрыть окно из команды viewmodel?

4b9b3361

Ответ 1

Вам не нужно передавать экземпляр View на ваш уровень ViewModel. Вы можете получить доступ к главному окну, например:

Application.Current.MainWindow.Close()

Я не вижу проблемы при доступе к вашему главному окну в классе ViewModel, как указано выше. В соответствии с принципом MVVM не должно быть жесткой связи между вашим представлением и ViewModel, то есть они должны работать, не обращая внимания на другие операции. Здесь мы ничего не передаем ViewModel из View. Если вы хотите найти другие варианты, это может вам помочь - Закрыть окно с помощью MVVM

Ответ 2

Я лично использую очень простой подход: для каждого ViewModel, связанного с закрытым представлением, я создал базовый ViewModel, как показано ниже:

public abstract class CloseableViewModel
{
    public event EventHandler ClosingRequest;

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

Затем в вашей ViewModel, которая наследуется от CloseableViewModel, просто вызовите this.OnClosingRequest(); для команды Close.

В представлении:

public class YourView
{
    ...
    var vm = new ClosableViewModel();
    this.Datacontext = vm;
    vm.ClosingRequest += (sender, e) => this.Close();
}

Ответ 3

Мое решение закрыть окно из модели просмотра при нажатии кнопки выглядит следующим образом:

В представлении модели

public RelayCommand CloseWindow;
Constructor()
{
    CloseWindow = new RelayCommand(CloseWin);
}

public void CloseWin(object obj)
{
    Window win = obj as Window;
    win.Close();
}

В представлении, установите следующим образом

<Button Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=WindowNameTobeClose}" Content="Cancel" />

Ответ 4

Я делаю это, создавая прикрепленное свойство DialogResult:

public static class DialogCloser
{
    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached(
            "DialogResult",
            typeof(bool?),
            typeof(DialogCloser),
            new PropertyMetadata(DialogResultChanged));

    private static void DialogResultChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window != null && (bool?)e.NewValue == true) 
                window.Close();
    }

    public static void SetDialogResult(Window target, bool? value)
    {
        target.SetValue(DialogResultProperty, value);
    }
}

затем напишите это вам XAML, в теге окна

WindowActions:DialogCloser.DialogResult="{Binding Close}"

наконец, в ViewModel

    private bool _close;
    public bool Close
    {
        get { return _close; }
        set
        {
            if (_close == value)
                return;
            _close = value;
            NotifyPropertyChanged("Close");
        }
    }

если вы измените Close на true, окно будет закрыто

Close = True;

Ответ 5

Остерегайтесь модных парадигм. MVVM может быть полезным, но вы действительно не должны относиться к нему как к жесткому набору правил. Используйте свое собственное мнение, и когда это не имеет смысла - не используйте его.

Решения, предлагаемые здесь (за исключением решения @RV1987), являются очень хорошим примером того, как выходить из рук. Вы заменяете один вызов Close() таким огромным количеством кода, с какой целью? Вы ничего не получаете от перемещения закрывающего кода из представления в модель представления. Единственное, что вы получаете, - это место для большего количества ошибок.

Теперь я не говорю, что MVVM следует игнорировать. Наоборот, это может быть очень полезно. Просто не делай этого.

Ответ 6

Вот самое простое и чистое решение MVVM

ViewModel Code

public class ViewModel
{
    public Action CloseAction { get; set; }

    private void CloseCommandFunction()
    {
        CloseAction();
    }
}

Вот XAML Посмотреть код

public partial class DialogWindow : Window
{
    public DialogWindow()
    {
        ViewModel vm = new ViewModel();
        this.DataContext = vm;

        vm.CloseAction = new Action(() => this.Close());
    }
}

Ответ 7

Это быстрое и простое решение. Недостатком является то, что между слоями существует некоторая связь.

В вашей модели просмотра:

public class MyWindowViewModel: ViewModelBase
{


    public Command.StandardCommand CloseCommand
    {
        get
        {
            return new Command.StandardCommand(Close);
        }
    }
    public void Close()
    {
        foreach (System.Windows.Window window in System.Windows.Application.Current.Windows)
        {
            if (window.DataContext == this)
            {
                window.Close();
            }
        }
    }
}

Ответ 8

MVVM-light с уведомлением пользовательского сообщения, чтобы избежать окна для обработки каждого сообщения уведомления

В viewmodel:

public class CloseDialogMessage : NotificationMessage
{
    public CloseDialogMessage(object sender) : base(sender, "") { }
}

private void OnClose()
{
    Messenger.Default.Send(new CloseDialogMessage(this));
}

Зарегистрировать сообщение в конструкторе окна:

Messenger.Default.Register<CloseDialogMessage>(this, nm =>
{
    Close();
});

Ответ 9

Это очень похоже на ответ eoldre. Это функционально то же самое в том, что он просматривает ту же коллекцию Windows для окна, которое имеет модель представления в качестве своего datacontext; но я использовал RelayCommand и некоторые LINQ для достижения того же результата.

public RelayCommand CloseCommand
{
    get
    {
        return new RelayCommand(() => Application.Current.Windows
            .Cast<Window>()
            .Single(w => w.DataContext == this)
            .Close());
    }
}

Ответ 10

с использованием инструментария MVVM-light:

В ViewModel:

 public void notifyWindowToClose()
{
    Messenger.Default.Send<NotificationMessage>(
        new NotificationMessage(this, "CloseWindowsBoundToMe")
    );
}

И в представлении:

 Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
    if (nm.Notification == "CloseWindowsBoundToMe")
    {
        if (nm.Sender == this.DataContext)
            this.Close();
    }
});

Ответ 11

Это взято из ответа ken2k (спасибо!), просто добавив CloseCommand также к базе CloseableViewModel.

public class CloseableViewModel
{
    public CloseableViewModel()
    {
        CloseCommand = new RelayCommand(this.OnClosingRequest);
    }

    public event EventHandler ClosingRequest;

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

    public RelayCommand CloseCommand
    {
        get;
        private set;
    }
}

Ваша модель просмотра наследует ее

public class MyViewModel : CloseableViewModel

Затем вы просматриваете

public MyView()
{
    var viewModel = new StudyDataStructureViewModel(studyId);
    this.DataContext = viewModel;

    //InitializeComponent(); ...

    viewModel.ClosingRequest += (sender, e) => this.Close();
}

Ответ 12

Учитывая способ, пожалуйста, проверьте

fooobar.com/questions/29614/...

Краткое описание

  • Вывести свою ViewModel из INotifyPropertyChanged
  • Создайте наблюдаемое свойство CloseDialog в ViewModel, измените свойство CloseDialog, когда вы хотите закрыть диалог.
  • Примените обработчик в представлении для этого изменения свойства
  • Теперь вы почти закончили. В обработчике событий make DialogResult = true

Ответ 13

прежде всего дайте вашему окну такое имя, как

x:Name="AboutViewWindow"

на моей кнопке закрытия Я определил параметр команды и команды, например

CommandParameter="{Binding ElementName=AboutViewWindow}"
Command="{Binding CancelCommand}"

то, на мой взгляд, модель

private ICommand _cancelCommand;        
public ICommand CancelCommand       
{
   get          
     {
        if (_cancelCommand == null)
           {
              _cancelCommand = new DelegateCommand<Window>(
                    x =>
                    {
                        x?.Close();
                    });
            }

            return _cancelCommand;          
     }      
}