Closing
확인 메시지를 표시하거나 닫기를 취소하기 위해 내 창의 이벤트 (사용자가 오른쪽 상단 ‘X’버튼을 클릭 할 때) 를 처리하고 싶습니다 .
코드 숨김 에서이 작업을 수행하는 방법을 알고 있습니다 : Closing
창의 이벤트에 가입 한 다음 CancelEventArgs.Cancel
속성 을 사용하십시오 .
그러나 MVVM을 사용하고 있으므로 좋은 접근 방법인지 잘 모르겠습니다.
좋은 접근 방식은 Closing
이벤트를 Command
내 ViewModel에서 바인딩하는 것 입니다.
나는 그것을 시도했다 :
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding CloseCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
RelayCommand
내 ViewModel에 관련 이 있지만 작동하지 않습니다 (명령 코드가 실행되지 않음).
답변
처리기를 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
}
이 경우보다 간접적 인 (XAML의 5 개의 추가 라인 + Command
패턴) 더 정교한 패턴을 사용하여 복잡성을 제외하고는 아무것도 얻을 수 없습니다 .
“제로 코드 비하인드”만트라 자체는 목표가 아니며 요점은 ViewModel과 View 분리하는 것 입니다. 이벤트가 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>
가정 :
- ViewModel은
DataContext
기본 컨테이너 중 하나 에 할당됩니다 . xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.SL5"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
답변
이 옵션은 훨씬 쉬우 며 아마도 적합 할 것입니다. 뷰 모델 생성자에서 다음과 같이 메인 창 닫기 이벤트를 구독 할 수 있습니다.
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();
}
ViewModel에서 인터페이스와 구현을 추가하십시오.
public bool OnClosing()
{
bool close = true;
//Ask whether to save changes och cancel etc
//close = false; //If you want to cancel close
return close;
}
창에서 Closing 이벤트를 추가합니다. 이 코드는 MVVM 패턴을 손상시키지 않습니다. 뷰는 뷰 모델에 대해 알 수 있습니다!
void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
IClosing context = DataContext as IClosing;
if (context != null)
{
e.Cancel = !context.OnClosing();
}
}
답변
이런, 여기에 많은 코드가있는 것 같습니다. 위의 통계는 최소한의 노력으로 올바른 접근 방식을 가졌습니다. 여기 내 적응이 있습니다 (MVVMLight를 사용하지만 인식 할 수 있어야합니다) … 아 그리고 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);
ShutdownService에서
/// <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를 사용하지 않는 독자에게는 내가 사용한 것을 시도해 볼 수 있습니다.
창 또는 usercontrol 등의 상단 정의에서 네임 스페이스를 정의하십시오.
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; }
viewmodel 생성자에 delegatecommand를 첨부하십시오.
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();
}
그런 다음 MainWindowViewModel 코드에서 다음을 가질 수 있습니다.
#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]