WPF/MVVM Light Toolkit을 사용한 창 닫기 이벤트 처리
그 일을 .Closing
이벤트(사용자가 오른쪽 위 'X' 버튼을 클릭했을 때)를 클릭하여 최종적으로 확인 메시지를 표시하거나 닫기를 취소합니다.
비하인드로 .서브스크라이브에 .Closing
합니다.CancelEventArgs.Cancel
★★★★★★★★★★★★★★★★★★.
하지만 저는 MVVM을 사용하고 있기 때문에 이것이 좋은 방법인지 잘 모르겠습니다.
은 '를 하는 합니다.Closing
Command
참조할 수 있습니다.
저도 해봤어요.
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding CloseCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
있는 「」를 사용해 .RelayCommand
동작하지 않습니다(명령어 코드는 실행되지 않습니다).
View 컨스트럭터에서 핸들러를 연결하기만 하면 됩니다.
MyWindow()
{
// Set up ViewModel, assign to DataContext etc.
Closing += viewModel.OnWindowClosing;
}
다음 '를 '핸들러'에 합니다.ViewModel
:
using System.ComponentModel;
public void OnWindowClosing(object sender, CancelEventArgs e)
{
// Handle closing logic, set e.Cancel as needed
}
이 보다 + 을이외에는 얻을 수 있는 .Command
□□□□□□□□★
코드 배후에 제로(zero code-behind)라는 주문 자체가 목적이 아니라 View Model을 View에서 분리하는 것이 핵심입니다.이벤트가 View의 코드 뒤에 바인딩되어 있는 경우에도ViewModel
뷰에 의존하지 않고 클로징 로직을 유닛 테스트 할 수 있습니다.
이 코드는 정상적으로 동작합니다.
ViewModel.cs:
public ICommand WindowClosing
{
get
{
return new RelayCommand<CancelEventArgs>(
(args) =>{
});
}
}
XAML의 경우:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<command:EventToCommand Command="{Binding WindowClosing}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
다음을 전제로 합니다.
- 은 View Model에 .
DataContext
츠미야 xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.SL5"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
이 옵션은 훨씬 더 쉽고 고객에게 적합할 수 있습니다.View Model 생성자에서 다음과 같이 기본 창 닫기 이벤트를 구독할 수 있습니다.
Application.Current.MainWindow.Closing += new CancelEventHandler(MainWindow_Closing);
void MainWindow_Closing(object sender, CancelEventArgs e)
{
//Your code to handle the event
}
행운을 빌어요.
다음은 ViewModel의 Window(또는 해당 이벤트)에 대해 알고 싶지 않은 경우 MVVM 패턴에 따른 답변입니다.
public interface IClosing
{
/// <summary>
/// Executes when window is closing
/// </summary>
/// <returns>Whether the windows should be closed by the caller</returns>
bool OnClosing();
}
View Model에서 인터페이스와 구현을 추가합니다.
public bool OnClosing()
{
bool close = true;
//Ask whether to save changes och cancel etc
//close = false; //If you want to cancel close
return close;
}
Window에서 Closing 이벤트를 추가합니다.뒤에 있는 이 코드는 MVVM 패턴을 파괴하지 않습니다.뷰는 뷰 모델에 대해 알 수 있습니다!
void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
IClosing context = DataContext as IClosing;
if (context != null)
{
e.Cancel = !context.OnClosing();
}
}
이런, 여기에 많은 암호들이 있는 것 같네요.위의 Stas는 최소한의 노력으로 올바른 접근 방식을 취했습니다.여기 적응이 있습니다(MVMLight를 사용하지만 인식할 수 있어야 함).Oh 및 PassEventArgsToCommand="True'는 위와 같이 반드시 필요합니다.
(Laurent Bugnion http://blog.galasoft.ch/archive/2009/10/18/clean-shutdown-in-silverlight-and-wpf-applications.aspx) 크레딧).
... MainWindow Xaml
...
WindowStyle="ThreeDBorderWindow"
WindowStartupLocation="Manual">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding WindowClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
뷰 모델:
///<summary>
/// public RelayCommand<CancelEventArgs> WindowClosingCommand
///</summary>
public RelayCommand<CancelEventArgs> WindowClosingCommand { get; private set; }
...
...
...
// Window Closing
WindowClosingCommand = new RelayCommand<CancelEventArgs>((args) =>
{
ShutdownService.MainWindowClosing(args);
},
(args) => CanShutdown);
셧다운 서비스로
/// <summary>
/// ask the application to shutdown
/// </summary>
public static void MainWindowClosing(CancelEventArgs e)
{
e.Cancel = true; /// CANCEL THE CLOSE - let the shutdown service decide what to do with the shutdown request
RequestShutdown();
}
RequestShutdown은 다음과 같이 보이지만 기본적으로 RequestShutdown 또는 그 이름이 무엇이든 응용 프로그램을 종료할지 여부를 결정합니다(어쨌든 창이 즐겁게 닫힙니다).
...
...
...
/// <summary>
/// ask the application to shutdown
/// </summary>
public static void RequestShutdown()
{
// Unless one of the listeners aborted the shutdown, we proceed. If they abort the shutdown, they are responsible for restarting it too.
var shouldAbortShutdown = false;
Logger.InfoFormat("Application starting shutdown at {0}...", DateTime.Now);
var msg = new NotificationMessageAction<bool>(
Notifications.ConfirmShutdown,
shouldAbort => shouldAbortShutdown |= shouldAbort);
// recipients should answer either true or false with msg.execute(true) etc.
Messenger.Default.Send(msg, Notifications.ConfirmShutdown);
if (!shouldAbortShutdown)
{
// This time it is for real
Messenger.Default.Send(new NotificationMessage(Notifications.NotifyShutdown),
Notifications.NotifyShutdown);
Logger.InfoFormat("Application has shutdown at {0}", DateTime.Now);
Application.Current.Shutdown();
}
else
Logger.InfoFormat("Application shutdown aborted at {0}", DateTime.Now);
}
}
질문자는 STAS 답변을 사용해야 하지만 프리즘을 사용하고 galasoft/mvvmlight를 사용하지 않는 독자는 내가 사용한 것을 시험해 보고 싶을 것이다.
창 또는 사용자 제어 등에 대한 맨 위의 정의에서 네임스페이스를 정의합니다.
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
그리고 그 정의 바로 아래:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding WindowClosing}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
뷰 모델의 속성:
public ICommand WindowClosing { get; private set; }
뷰 모델 생성자에서 delegate 명령 연결:
this.WindowClosing = new DelegateCommand<object>(this.OnWindowClosing);
마지막으로 컨트롤/창/무엇을 닫을 때 연결할 코드:
private void OnWindowClosing(object obj)
{
//put code here
}
저는 당신의 App.xaml.cs 파일 내에 있는 이벤트 핸들러를 사용하고 싶습니다.이것에 의해, 애플리케이션을 종료할지를 결정할 수 있게 됩니다.
예를 들어, App.xaml.cs 파일에 다음과 같은 코드가 있을 수 있습니다.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// Create the ViewModel to attach the window to
MainWindow window = new MainWindow();
var viewModel = new MainWindowViewModel();
// Create the handler that will allow the window to close when the viewModel asks.
EventHandler handler = null;
handler = delegate
{
//***Code here to decide on closing the application****
//***returns resultClose which is true if we want to close***
if(resultClose == true)
{
viewModel.RequestClose -= handler;
window.Close();
}
}
viewModel.RequestClose += handler;
window.DataContaxt = viewModel;
window.Show();
}
그런 다음 Main Window View Model 코드 내에서 다음을 사용할 수 있습니다.
#region Fields
RelayCommand closeCommand;
#endregion
#region CloseCommand
/// <summary>
/// Returns the command that, when invoked, attempts
/// to remove this workspace from the user interface.
/// </summary>
public ICommand CloseCommand
{
get
{
if (closeCommand == null)
closeCommand = new RelayCommand(param => this.OnRequestClose());
return closeCommand;
}
}
#endregion // CloseCommand
#region RequestClose [event]
/// <summary>
/// Raised when this workspace should be removed from the UI.
/// </summary>
public event EventHandler RequestClose;
/// <summary>
/// If requested to close and a RequestClose delegate has been set then call it.
/// </summary>
void OnRequestClose()
{
EventHandler handler = this.RequestClose;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
#endregion // RequestClose [event]
기본적으로 윈도우 이벤트는 MVVM에 할당되지 않을 수 있습니다.일반적으로 닫기 버튼에는 사용자에게 "save: yes/no/cancel(저장: 예/아니오/취소)"을 요청하는 대화상자가 표시되며, MVVM에서는 이 작업이 수행되지 않을 수 있습니다.
모델을 호출하는 OnClosing 이벤트 핸들러를 유지할 수 있습니다.canExecute()를 닫고 이벤트 속성에 부울 결과를 설정합니다.따라서 CanExecute() 호출(true인 경우) 후 또는 OnClosed 이벤트에서 모델을 호출합니다.Close.Execute()
이걸로 테스트를 많이 해보진 않았지만 효과가 있는 것 같아요.제가 생각해낸 것은 다음과 같습니다.
namespace OrtzIRC.WPF
{
using System;
using System.Windows;
using OrtzIRC.WPF.ViewModels;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private MainViewModel viewModel = new MainViewModel();
private MainWindow window = new MainWindow();
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
viewModel.RequestClose += ViewModelRequestClose;
window.DataContext = viewModel;
window.Closing += Window_Closing;
window.Show();
}
private void ViewModelRequestClose(object sender, EventArgs e)
{
viewModel.RequestClose -= ViewModelRequestClose;
window.Close();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
window.Closing -= Window_Closing;
viewModel.RequestClose -= ViewModelRequestClose; //Otherwise Close gets called again
viewModel.CloseCommand.Execute(null);
}
}
}
여기에는 AttachedCommandBehavior를 사용합니다.모든 이벤트를 뷰 모델의 명령에 첨부하여 코드 뒤에 표시되지 않도록 할 수 있습니다.
솔루션 전체에서 사용하고 있으며, 코드 배후에 거의 없음
http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/
MVVM Light Toolkit 사용:
뷰 모델에 Exit 명령어가 있다고 가정합니다.
ICommand _exitCommand;
public ICommand ExitCommand
{
get
{
if (_exitCommand == null)
_exitCommand = new RelayCommand<object>(call => OnExit());
return _exitCommand;
}
}
void OnExit()
{
var msg = new NotificationMessageAction<object>(this, "ExitApplication", (o) =>{});
Messenger.Default.Send(msg);
}
이것은 뷰로 수신됩니다.
Messenger.Default.Register<NotificationMessageAction<object>>(this, (m) => if (m.Notification == "ExitApplication")
{
Application.Current.Shutdown();
});
저는 른른른른른, 는는 on on를 취급하고 .Closing
의 사건MainWindow
모델 표시:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (((ViewModel.MainViewModel)DataContext).CancelBeforeClose())
e.Cancel = true;
}
CancelBeforeClose
는 현재 뷰 모델 상태를 확인하고 닫기를 중지해야 하는 경우 true를 반환합니다.
도움이 됐으면 좋겠는데
저는 이 투고에서 영감을 얻어 이 투고를 저만의 용도로 만들고 있는 라이브러리로 개조했습니다(단, 공개 장소는 https://github.com/RFBCodeWorks/MvvmControls입니다).
핸들러에 전달되는 '송신자' 및 '이벤트args'를 통해 View Model에 View가 어느 정도 노출되지만, 다른 종류의 처리에 필요할 경우에 대비하여 이 방법을 사용했습니다.예를 들어 핸들러가 ViewModel이 아니라 창 열기/닫기 시간을 기록하는 서비스인 경우 해당 서비스는 발신인에 대해 알고 싶어할 수 있습니다.VM이 View에 대해 알고 싶지 않은 경우 송신자 또는 arg를 검사하지 않습니다.
다음은 제가 생각해낸 관련 코드입니다. 코드 이면을 제거하고 xaml 내에서 바인딩을 허용합니다.
Behaviors:WindowBehaviors.IWindowClosingHandler="{Binding ElementName=ThisWindow, Path=DataContext}"
/// <summary>
/// Interface that can be used to send a signal from the View to the ViewModel that the window is closing
/// </summary>
public interface IWindowClosingHandler
{
/// <summary>
/// Executes when window is closing
/// </summary>
void OnWindowClosing(object sender, System.ComponentModel.CancelEventArgs e);
/// <summary>
/// Occurs when the window has closed
/// </summary>
void OnWindowClosed(object sender, EventArgs e);
}
/// <summary>
/// Attached Properties for Windows that allow MVVM to react to a window Loading/Activating/Deactivating/Closing
/// </summary>
public static class WindowBehaviors
{
#region < IWindowClosing >
/// <summary>
/// Assigns an <see cref="IWindowClosingHandler"/> handler to a <see cref="Window"/>
/// </summary>
public static readonly DependencyProperty IWindowClosingHandlerProperty =
DependencyProperty.RegisterAttached(nameof(IWindowClosingHandler),
typeof(IWindowClosingHandler),
typeof(WindowBehaviors),
new PropertyMetadata(null, IWindowClosingHandlerPropertyChanged)
);
/// <summary>
/// Gets the assigned <see cref="IWindowLoadingHandler"/> from a <see cref="Window"/>
/// </summary>
public static IWindowClosingHandler GetIWindowClosingHandler(DependencyObject obj) => (IWindowClosingHandler)obj.GetValue(IWindowClosingHandlerProperty);
/// <summary>
/// Assigns an <see cref="IWindowClosingHandler"/> to a <see cref="Window"/>
/// </summary>
public static void SetIWindowClosingHandler(DependencyObject obj, IWindowClosingHandler value)
{
if (obj is not null and not Window) throw new ArgumentException($"{nameof(IWindowClosingHandler)} property can only be bound to a {nameof(Window)}");
obj.SetValue(IWindowClosingHandlerProperty, value);
}
private static void IWindowClosingHandlerPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Window w = d as Window;
if (w is null) return;
if (e.NewValue != null)
{
w.Closing += W_Closing;
w.Closed += W_Closed;
}
else
{
w.Closing -= W_Closing;
w.Closed -= W_Closed;
}
}
private static void W_Closed(object sender, EventArgs e)
{
GetIWindowClosingHandler(sender as DependencyObject)?.OnWindowClosed(sender, e);
}
private static void W_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
GetIWindowClosingHandler(sender as DependencyObject)?.OnWindowClosing(sender, e);
}
#endregion
}
뒤에 있는 코드를 사용하면 쉽게 할 수 있습니다.Main.xaml에서는 다음과 같이 설정됩니다.Closing="Window_Closing"
Main.cs의 경우:
public MainViewModel dataContext { get; set; }
public ICommand CloseApp
{
get { return (ICommand)GetValue(CloseAppProperty); }
set { SetValue(CloseAppProperty, value); }
}
public static readonly DependencyProperty CloseAppProperty =
DependencyProperty.Register("CloseApp", typeof(ICommand), typeof(MainWindow), new PropertyMetadata(null));
메인.온로드:
dataContext = DataContext as MainViewModel;
메인.창_닫기:
if (CloseApp != null)
CloseApp .Execute(this);
Main Window Model에서:
public ICommand CloseApp => new CloseApp (this);
그리고 마지막으로:
Class Close App : ICommand { public event Handler Can Execute Changed ;
private MainViewModel _viewModel;
public CloseApp (MainViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
Console.WriteLine();
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
MessageBox.Show("closing");
}
언급URL : https://stackoverflow.com/questions/3683450/handling-the-window-closing-event-with-wpf-mvvm-light-toolkit
'code' 카테고리의 다른 글
PowerShell을 사용하여 디렉토리 내의 파일을 루프합니다. (0) | 2023.04.23 |
---|---|
C#을 사용하여 폴더에서 모든 파일 이름 가져오기 (0) | 2023.04.23 |
Excel 파일의 올바른 콘텐츠 유형은 무엇입니까? (0) | 2023.04.23 |
ENV 변수 또는 기본값을 사용하여 Makefile 변수 정의 (0) | 2023.04.23 |
세로 구분 기호를 추가하는 방법 (0) | 2023.04.23 |