WPF MVVM: 창을 닫는 방법
는 나나 a a a가 있다Button
이치노
<Button x:Name="buttonOk" IsCancel="True">Ok</Button>
저는 그면 a a .Command
Button
말해
<Button x:Name="buttonOk"
Command="{Binding SaveCommand}"
IsCancel="True">Ok</Button>
겁니다.Command
하면 수 EventHandler
및 콜링this.Close()
ㅇㅇㅇ.
<Button x:Name="buttonOk"
Click="closeWindow"
Command="{Binding SaveCommand}"
IsCancel="True">Ok</Button>
내 에는 코드가 지지이 、 법 but 、 but but 、 but but 、 법 but 。SaveCommand
과 MVVM을 SaveCommand
뒤에 있는 내 코드의 유일한 코드야
뒤에 있는 코드를 사용하지 않도록 하려면 어떻게 해야 합니까?
나는 바로 이 주제에 대한 블로그 투고를 막 완성했다.간단히 말하면,Action
get
★★★★★★★★★★★★★★★★★」set
그럼 이렇게 정의해 .Action
의 서 View
창을합니다.마지막으로 창을 닫아야 하는 bound 명령어로 액션을 호출합니다.
View Model에서:
public Action CloseAction { get; set;}
,에는View
★★★★★★★★★★★★★★★★★★:
private View()
{
InitializeComponent();
ViewModel vm = new ViewModel();
this.DataContext = vm;
if ( vm.CloseAction == null )
vm.CloseAction = new Action(this.Close);
}
마지막으로 창을 닫아야 하는 바인딩된 명령어에서는 단순히 호출할 수 있습니다.
CloseAction(); // Calls Close() method of the View
이것은 나에게 효과가 있었고, 꽤 우아한 해결책처럼 보였고, 많은 코딩을 줄일 수 있었다.
은 MVVM을 사용하는 입니다.InteractionTrigger
★★★★★★★★★★★★★★★★★」CallMethodAction
되어 있습니다.Microsoft.Interactivity.Core
다음과 같이 새 네임스페이스를 추가해야 합니다.
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
Microsoft.Xmal 이 필요합니다.행동.WPF 어셈블리와 다음 xaml 코드가 동작합니다.
<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>
도 필요 할 수 .Window
.
댓글에 따르면 제가 올린 코드는 MVVM 친화적이지 않습니다만, 두 번째 솔루션은 어떻습니까?
첫째, MVVM 솔루션이 아닙니다(이것을 참조로 삭제하지 않습니다).
XAML:
<Button Name="okButton" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">OK</Button>
뷰 모델:
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; }
두 번째, 아마도 더 나은 솔루션:부속 행동 사용
XAML
<Button Content="Ok and Close" Command="{Binding OkCommand}" b:CloseOnClickBehaviour.IsEnabled="True" />
모델 표시
public ICommand OkCommand
{
get { return _okCommand; }
}
행동 클래스 다음과 유사한 것:
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();
}
}
나는 개인적으로 이런 종류의 일을 할 때 행동을 취할 것이다.
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();
};
}
}
이 수 있습니다.Window
★★★★★★★★★★★★★★★★★」Button
★★★★
<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>
추가했습니다.Command
★★★★★★★★★★★★★★★★★」CommandParameter
할 수 .Window
힙니니다
소규모 앱의 경우 창과 DataContext를 표시, 닫기 및 삭제하기 위해 자체 Application Controller를 사용합니다.응용 프로그램 UI의 중앙 지점입니다.
다음과 같습니다.
//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();
}
}
및 View Model로부터의 호출:
// Show new Window with DataContext
ApplicationController.Instance.ShowNewWindow(
new ClientCardsWindow(),
new ClientCardsVM(),
false);
// Close Current Window from viewModel
ApplicationController.Instance.CloseWindow(this);
물론 제 솔루션에서 몇 가지 제한을 찾을 수 있습니다.다시 말씀드리지만, 저는 이 제품을 소규모 프로젝트에 사용하고 있습니다.이것으로 충분합니다.관심있으시면 여기나 다른 곳에 풀코드를 올릴 수 있습니다.
일반적인 MVVM 방식으로 이 문제를 해결하려고 시도했지만, 항상 불필요한 복잡한 논리로 끝납니다.근접한 동작을 얻기 위해 코드 뒤에 있는 no code behind 규칙에서 예외를 만들고 코드 뒤에 있는 good ol' events를 단순히 사용합니다.
XAML:
<Button Content="Close" Click="OnCloseClicked" />
코드 배면:
private void OnCloseClicked(object sender, EventArgs e)
{
Visibility = Visibility.Collapsed;
}
명령어/MVVM을 사용하는 것이 더 잘 지원되었으면 좋겠지만, 이벤트를 사용하는 것보다 더 간단하고 명확한 솔루션은 없다고 생각합니다.
복잡한 클래스 의존관계에는 Publish Subscribe 패턴을 사용합니다.
뷰 모델:
public class ViewModel : ViewModelBase
{
public ViewModel()
{
CloseComand = new DelegateCommand((obj) =>
{
MessageBus.Instance.Publish(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, null);
});
}
}
창:
public partial class SomeWindow : Window
{
Subscription _subscription = new Subscription();
public SomeWindow()
{
InitializeComponent();
_subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj =>
{
this.Close();
});
}
}
Bizmonger를 활용할 수 있습니다.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
}
}
서브스크립션
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);
}
}
이 작업에는 View가 ViewModel 내에서 완전히 정의된 명령에 연결되도록 Expression Blend 3에서 도입된 MVVM(동작)을 중단하지 않는 유용한 동작이 있습니다.
이 동작은 ViewModel이 Model-ViewModel 응용 프로그램에서 View의 닫힘 이벤트를 관리할 수 있도록 하는 간단한 기술을 보여줍니다.
이를 통해 View(UserControl)에서 동작을 연결하면 컨트롤의 창을 제어할 수 있으며 ViewModel은 표준 ICommand를 통해 창을 닫을 수 있는지 여부를 제어할 수 있습니다.
동작을 사용하여 View Model이 M-V-VM의 View 수명을 관리할 수 있도록 허용
http://gallery.expression.microsoft.com/WindowCloseBehavior/
위의 링크는 http://code.msdn.microsoft.com/Window-Close-Attached-fef26a66#content에 아카이브 되었습니다.
한동안 이 주제에 대해 고민하다가 결국 MVVM과 일관성이 있는 가장 단순한 접근방식을 택했습니다.즉, 버튼에서 모든 무거운 작업을 수행하는 명령을 실행하고 버튼의 클릭 핸들러를 사용하여 창을 닫습니다.
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!
사실, 여전히 코드 배후에 있는 것은 사실이지만, 그것에 대해 본질적으로 나쁜 것은 아닙니다.그리고 OO의 관점에서 보면 창문을 닫으라고 말하는 것이 가장 말이 됩니다.
.xaml 정의에는 다음과 같은 이름 속성이 있습니다.
x:Name="WindowsForm"
그런 다음 버튼이 있습니다.
<Button Command="{Binding CloseCommand}"
CommandParameter="{Binding ElementName=WindowsForm}" />
그런 다음 ViewModel에서 다음을 수행합니다.
public DelegateCommand <Object> CloseCommand { get; private set; }
Constructor for that view model:
this.CloseCommand = new DelegateCommand<object>(this.CloseAction);
마지막으로 액션 방법은 다음과 같습니다.
private void CloseAction (object obj)
{
Window Win = obj as Window;
Win.Close();
}
이 코드를 사용하여 응용 프로그램에서 팝업 창을 닫았습니다.
에 근거한 WPF 어플리케이션에서 이 작업을 수행해야 한다는 것을 알게 되었습니다.Net Core 3.0. 유감스럽게도 동작 지원은 아직 Microsoft에서 공식적으로 제공되지 않았습니다.젬, 행동가들Wpf NuGet 패키지
대신 파사드 디자인 패턴을 활용한 솔루션을 선택하였습니다.
인터페이스:
public interface IWindowFacade
{
void Close();
}
창:
public partial class MainWindow : Window, IWindowFacade
…
뷰 모델의 표준 명령 속성:
public ICommand ExitCommand
…
제어 바인딩:
<MenuItem Header="E_xit" Command="{Binding ExitCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
명령어:
public class ExitCommand : ICommand
{
…
public void Execute(object parameter)
{
var windowFacade = parameter as IWindowFacade;
windowFacade?.Close();
}
…
}
왜냐하면Close()
메서드는 이미 에 의해 구현되어 있습니다.Window
클래스, 창에 전면 인터페이스를 적용하는 것이 UI 레이어 뒤에 필요한 유일한 코드입니다(이 간단한 예에서는).이 프레젠테이션레이어의 명령어는 view/UI 레이어가 콜할 때 무엇을 통신하고 있는지 알 수 없기 때문에 view/UI 레이어에 대한 의존을 회피합니다.Close
파사드의 방법.
현재 창에서xaml.cs
파일, 다음 코드를 호출합니다.
var curWnd = Window.GetWindow(this); // passing current window context
curWnd?.Close();
이거면 될 거야
나에게도 효과가 있었고, 희망도 당신에게도 같은 일을 할 것입니다.
Silverlight에는 다음과 같은 솔루션이 있습니다.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();
}
}
}
Item Window.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>
좋은 아이디어와 프로젝트를 모두 기원합니다;-)
이 방법은 mvvm을 사용하여 wpf 창을 닫는 데 도움이 될 수 있습니다. http://jkshay.com/closing-a-wpf-window-using-mvvm-and-minimal-code-behind/
가장 간단한 방법은 아직 포함되지 않은 것 같다.새로운 종속성을 추가하는 행동을 사용하는 대신 첨부된 속성을 사용하십시오.
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;
}
}
그런 다음 대화상자 버튼으로 설정합니다.
<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>
저도 이 문제에 대처해야 했기 때문에, 여기 제 해결책이 있습니다.나한테는 잘 먹힌다.
1. 클래스 Delegate Command를 만듭니다.
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. 명령어를 정의합니다.
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. 뷰에서 명령어를 바인드합니다.
public MyView(Window win) //ctor of your view, window as parameter
{
InitializeComponent();
MyButton.CommandParameter = win;
MyButton.Command = ((MyViewModel)this.DataContext).CloseWindowCommand;
}
4. 그리고 이제 창문은
Window win = new Window()
{
Title = "My Window",
Height = 800,
Width = 800,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
};
win.Content = new MyView(win);
win.ShowDialog();
따라서 명령어를 xaml 파일로 바인드하고 FindAncestor를 사용하여 창을 검색하여 명령어파라미터에 바인드할 수도 있습니다.
같은 문제에 대한 해결책을 찾고 있는데, 다음 방법으로도 문제가 없다는 것을 알게 되었습니다.이 솔루션은 OP가 질문에서 언급한 것과 비슷하지만 몇 가지 차이점이 있습니다.
할 필요가 없다
IsCancel
소유물.뒤에 있는 코드는 창을 닫으면 안 됩니다.셋팅 완료
DialogResult
내 경우 먼저 뒤에 있는 코드를 실행하고 다음으로 버튼에 바인딩된 모델 명령을 봅니다.
XAML
<Button x:Name="buttonOk" Click="Save_Click" Command="{Binding SaveCommand}">OK</Button>
코드 이면
private void Apply_OnClick(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
모델 표시
private void Save()
{
// Save data.
}
이게 도움이 됐으면 좋겠다.
질문을 바꿔서 다른 해결책을 생각해 보세요.MVVM 환경에서 뷰, 뷰 모델 등의 통신을 활성화하려면 어떻게 해야 합니까?Mediator 패턴을 사용할 수 있습니다.기본적으로 알림 시스템입니다.실제 Mediator 구현에 대해서는 구글에서 검색하거나 저에게 요청하시면 이메일로 보내드리겠습니다.
보기를 닫는 것을 목적으로 하는 명령을 만듭니다.
public void Execute( object parameter )
{
this.viewModel.DisposeMyStuff();
Mediator.NotifyColleagues(Mediator.Token.ConfigWindowShouldClose);
}
중개인은 통지(토큰)를 발행합니다.
View code behind 컨스트럭터에서 다음과 같은 알림(토큰)을 재생합니다.
public ClientConfigView()
{
InitializeComponent();
Mediator.ListenOn(Mediator.Token.ConfigWindowShouldClose, callback => this.Close() );
}
wpf에서 창을 닫는 솔루션이 정상적으로 동작하고 있는 경우는, 여기에 회답이 없기 때문에, 솔루션도 추가하려고 생각하고 있습니다.
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.
// }
}
다음과 같이 창의 버튼에 Close Window 이벤트를 추가합니다.
<Button Content="Cancel" Click="CloseWindow" >
간단한 접근법은 saveComand Implementation의 창을 닫는 것입니다.아래 코드를 사용하여 창을 닫습니다.
Application.Current.Windows[1].Close();
그러면 하위 창이 닫힙니다.
아무런 의존관계도 없이.
<Window ...>
...
<Button Command="{x:Static SystemCommands.CloseWindowCommand}" />
</Window>
코드 없이 할 수 있어요.명령어를 만듭니다. 뷰 모델의 Execute 메서드에서는 "Save" 메서드를 호출하고 편집 창의 콜 종료 메서드를 호출합니다.이 메서드는 파라미터로 명령어는 다음과 같습니다.
public void Execute(object parameter)
{
_mainViewModel.SaveSomething();
var editWindow = parameter as MyEditWindow;
editWindow?.Close();
}
저장 후 닫기 버튼 XAML:
<Button Content"Save&Close" Command="{Binding SaveCmd}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" IsDefault="True" />
언급URL : https://stackoverflow.com/questions/4376475/wpf-mvvm-how-to-close-a-window
'programing' 카테고리의 다른 글
Git 별칭 나열 (0) | 2023.04.22 |
---|---|
윈도우즈 10에서 환경 변수가 너무 큽니다. (0) | 2023.04.22 |
"find" 명령어 결과를 Bash에 배열로 저장하려면 어떻게 해야 합니다. (0) | 2023.04.22 |
셸 스크립트에서 디렉토리 내의 파일 목록을 가져오려면 어떻게 해야 합니까? (0) | 2023.04.17 |
git에서 삭제된 파일의 스테이징 해제 (0) | 2023.04.17 |