source

뷰 모델에서 창 닫기

manycodes 2023. 5. 11. 21:36
반응형

뷰 모델에서 창 닫기

를 하여 로그인 window controlWPF내가 만들고 있는 응용프로그램.

지금까지 사용자가 올바른 자격 증명을 입력했는지 확인하는 방법을 만들었습니다.username그리고.password순식간에textbox에서, 로인화서에면,bindingproperties.

나는 이것을 창조함으로써 성취했습니다.bool 법와방, 같이은;;

public bool CheckLogin()
{
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome " + user.Username + ", you have successfully logged in.");

        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
}

public ICommand ShowLoginCommand
{
    get
    {
        if (this.showLoginCommand == null)
        {
            this.showLoginCommand = new RelayCommand(this.LoginExecute, null);
        }
        return this.showLoginCommand;
    }
}

private void LoginExecute()
{
    this.CheckLogin();
} 

저도 있습니다.command가 는나한 것bind 단에추내 의 내 xaml식으로; 와같이이;이;

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" />

내가 사용자 이름과 비밀번호를 입력하면 그것은 그것이 옳든 그르든 적절한 코드를 실행합니다.그러나 사용자 이름과 암호가 모두 올바른 경우 View Model에서 이 창을 닫으려면 어떻게 해야 합니까?

▁a▁using다를 사용해 본 적이 .dialog modal하지만 잘 되지 않았습니다.또한, 제 앱.xaml 내에서 로그인 페이지를 먼저 로드한 다음, 사실이 되면 실제 애플리케이션을 로드하는 다음과 같은 작업을 수행했습니다.

private void ApplicationStart(object sender, StartupEventArgs e)
{
    Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;

    var dialog = new UserView();

    if (dialog.ShowDialog() == true)
    {
        var mainWindow = new MainWindow();
        Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
        Current.MainWindow = mainWindow;
        mainWindow.Show();
    }
    else
    {
        MessageBox.Show("Unable to load application.", "Error", MessageBoxButton.OK);
        Current.Shutdown(-1);
    }
}

질문:.로그인을 닫으려면 어떻게 해야 합니까?Window controlView 모델에서?

잘 부탁드립니다.

Model을 할 수 .CommandParameter아래의 예를 참조하십시오.

구습니다를 했습니다.CloseWindowWindows를 매개 변수로 사용하고 닫는 메서드입니다.은 창다 통로 전달 됩니다를 통해 됩니다.CommandParameter로 "" "" " " "는 .x:Name닫아야 할 창문을 위해.는 "XAML 호에를출다니합드서메"를 통해 이 합니다.Command를 매개 로 사용하여 합니다.CommandParameter.

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}"

모델 보기

public RelayCommand<Window> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
}

private void CloseWindow(Window window)
{
    if (window != null)
    {
       window.Close();
    }
}

보다

<Window x:Class="ClientLibTestTool.ErrorView"
        x:Name="TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:localization="clr-namespace:ClientLibTestTool.ViewLanguages"
        DataContext="{Binding Main, Source={StaticResource Locator}}"
        Title="{x:Static localization:localization.HeaderErrorView}"
        Height="600" Width="800"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen">
    <Grid> 
        <Button Content="{x:Static localization:localization.ButtonClose}" 
                Height="30" 
                Width="100" 
                Margin="0,0,10,10" 
                IsCancel="True" 
                VerticalAlignment="Bottom" 
                HorizontalAlignment="Right" 
                Command="{Binding CloseWindowCommand, Mode=OneWay}" 
                CommandParameter="{Binding ElementName=TestWindow}"/>
    </Grid>
</Window>

MVVM 라이트 프레임워크를 사용하고 있지만 모든 wpf 애플리케이션에 적용됩니다.

이 솔루션은 보기 모델이 UI 구현에 대해 아무것도 알지 못하기 때문에 MVVM 패턴을 위반합니다.MVVM 프로그래밍 패러다임을 엄격하게 따르려면 인터페이스를 사용하여 보기 유형을 추상화해야 합니다.

MVVM 준수 솔루션(이전 EDIT2)

사용자 크로노가 설명 섹션에서 유효한 점을 언급합니다.

Window 개체를 뷰 모델로 전달하면 MVVM 패턴 IMHO가 중단됩니다. 이는 VM에서 표시되는 내용을 알 수 있도록 하기 때문입니다.

클로즈 메소드가 포함된 인터페이스를 도입하여 이 문제를 해결할 수 있습니다.

인터페이스:

public interface ICloseable
{
    void Close();
}

리팩터링 뷰 모델은 다음과 같습니다.

모델 보기

public RelayCommand<ICloseable> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<IClosable>(this.CloseWindow);
}

private void CloseWindow(ICloseable window)
{
    if (window != null)
    {
        window.Close();
    }
}

다음을 참조하고 구현해야 합니다.ICloseable in your in view)

보기(코드 뒤에 있음)

public partial class MainWindow : Window, ICloseable
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

원래 질문에 대한 답변: (이전 EDIT1)

로그인 버튼(추가된 명령 매개 변수):

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" CommandParameter="{Binding ElementName=LoginWindow}"/>

코드:

 public RelayCommand<Window> CloseWindowCommand { get; private set; } // the <Window> is important for your solution!

 public MainViewModel() 
 {
     //initialize the CloseWindowCommand. Again, mind the <Window>
     //you don't have to do this in your constructor but it is good practice, thought
     this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
 }

 public bool CheckLogin(Window loginWindow) //Added loginWindow Parameter
 {
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome "+ user.Username + ", you have successfully logged in.");
        this.CloseWindow(loginWindow); //Added call to CloseWindow Method
        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
 }

 //Added CloseWindow Method
 private void CloseWindow(Window window)
 {
     if (window != null)
     {
         window.Close();
     }
 }

나는 보통 이 작업이 필요할 때 뷰 모델에 이벤트를 배치한 다음 이벤트를 연결합니다.Window.Close()때 델 바 인 딩

public class LoginViewModel
{
    public event EventHandler OnRequestClose;

    private void Login()
    {
        // Login logic here
        OnRequestClose(this, new EventArgs());
    }
}

로그인 창을 만들 때

var vm = new LoginViewModel();
var loginWindow = new LoginWindow
{
    DataContext = vm
};
vm.OnRequestClose += (s, e) => loginWindow.Close();

loginWindow.ShowDialog(); 

MVVM을 유지하면서 Blend SDK(System)의 Behaviors 중 하나를 사용하는 것 같습니다.창문들.상호 작용) 또는 프리즘의 사용자 지정 상호 작용 요청은 이러한 상황에서 매우 잘 작동할 수 있습니다.

행동 경로를 선택할 경우 일반적인 아이디어는 다음과 같습니다.

public class CloseWindowBehavior : Behavior<Window>
{
    public bool CloseTrigger
    {
        get { return (bool)GetValue(CloseTriggerProperty); }
        set { SetValue(CloseTriggerProperty, value); }
    }

    public static readonly DependencyProperty CloseTriggerProperty =
        DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(CloseWindowBehavior), new PropertyMetadata(false, OnCloseTriggerChanged));

    private static void OnCloseTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = d as CloseWindowBehavior;

        if (behavior != null)
        {
            behavior.OnCloseTriggerChanged();
        }
    }

    private void OnCloseTriggerChanged()
    {
        // when closetrigger is true, close the window
        if (this.CloseTrigger)
        {
            this.AssociatedObject.Close();
        }
    }
}

그런 다음 창에서 CloseTrigger를 창을 닫을 때 설정되는 부울 값으로 바인딩하면 됩니다.

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:TestApp"
        Title="MainWindow" Height="350" Width="525">
    <i:Interaction.Behaviors>
        <local:CloseWindowBehavior CloseTrigger="{Binding CloseTrigger}" />
    </i:Interaction.Behaviors>

    <Grid>

    </Grid>
</Window>

마지막으로 DataContext/ViewModel에는 다음과 같이 창을 닫을 때 설정한 속성이 있습니다.

public class MainWindowViewModel : INotifyPropertyChanged
{
    private bool closeTrigger;

    /// <summary>
    /// Gets or Sets if the main window should be closed
    /// </summary>
    public bool CloseTrigger
    {
        get { return this.closeTrigger; }
        set
        {
            this.closeTrigger = value;
            RaisePropertyChanged(nameof(CloseTrigger));
        }
    }

    public MainWindowViewModel()
    {
        // just setting for example, close the window
        CloseTrigger = true;
    }

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

창을 설정합니다.DataContext = 새 주창 보기 모델()

늦을지도 모르지만, 여기 제 대답이 있습니다.

foreach (Window item in Application.Current.Windows)
{
    if (item.DataContext == this) item.Close();
}

여기 제가 여러 프로젝트에서 사용한 것이 있습니다.해킹처럼 보일 수도 있지만 잘 작동합니다.

public class AttachedProperties : DependencyObject //adds a bindable DialogResult to window
{
    public static readonly DependencyProperty DialogResultProperty = 
        DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(AttachedProperties), 
        new PropertyMetaData(default(bool?), OnDialogResultChanged));

    public bool? DialogResult
    {
        get { return (bool?)GetValue(DialogResultProperty); }
        set { SetValue(DialogResultProperty, value); }
    }

    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window == null)
            return;

        window.DialogResult = (bool?)e.NewValue;
    }
}

이제 바인딩할 수 있습니다.DialogResultVM에 할당하고 속성 값을 설정합니다.Window값이 설정되면 닫힙니다.

<!-- Assuming that the VM is bound to the DataContext and the bound VM has a property DialogResult -->
<Window someNs:AttachedProperties.DialogResult={Binding DialogResult} />

이는 프로덕션 환경에서 실행되는 기능을 요약한 것입니다.

<Window x:Class="AC.Frontend.Controls.DialogControl.Dialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl" 
        xmlns:hlp="clr-namespace:AC.Frontend.Helper"
        MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
        WindowStartupLocation="CenterScreen" Title="{Binding Title}"
        hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True"
        Language="{Binding UiCulture, Source={StaticResource Strings}}">
        <!-- A lot more stuff here -->
</Window>

것처럼 인 보다시피, 이공을선니다언을 xmlns:hlp="clr-namespace:AC.Frontend.Helper"처음과 나중의 제본.hlp:AttachedProperties.DialogResult="{Binding DialogResult}".

AttachedProperty이렇게 생겼어요.어제 올린 것과 동일하지는 않지만, IMHO는 아무런 영향이 없을 것입니다.

public class AttachedProperties
{
    #region DialogResult

    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged));

    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var wnd = d as Window;
        if (wnd == null)
            return;

        wnd.DialogResult = (bool?) e.NewValue;
    }

    public static bool? GetDialogResult(DependencyObject dp)
    {
        if (dp == null) throw new ArgumentNullException("dp");

        return (bool?)dp.GetValue(DialogResultProperty);
    }

    public static void SetDialogResult(DependencyObject dp, object value)
    {
        if (dp == null) throw new ArgumentNullException("dp");

        dp.SetValue(DialogResultProperty, value);
    }

    #endregion
}

쉬운 방법

public interface IRequireViewIdentification
{
    Guid ViewID { get; }
}

모델을 보기 위해 구현

public class MyViewVM : IRequireViewIdentification
{
    private Guid _viewId;

    public Guid ViewID
    {
        get { return _viewId; }
    }

    public MyViewVM()
    {
        _viewId = Guid.NewGuid();
    }
}

일반 창 관리자 도우미 추가

public static class WindowManager
{
    public static void CloseWindow(Guid id)
    {
        foreach (Window window in Application.Current.Windows)
        {
            var w_id = window.DataContext as IRequireViewIdentification;
            if (w_id != null && w_id.ViewID.Equals(id))
            {
                window.Close();
            }
        }
    }
}

뷰 모델에서 이렇게 닫습니다.

WindowManager.CloseWindow(ViewID);

이것은 어떻습니까?

모델 보기:

class ViewModel
{
    public Action CloseAction { get; set; }
    private void Stuff()
    {
       // Do Stuff
       CloseAction(); // closes the window
    }
}

View Model에서 CloseAction()을 사용하여 위의 예와 같이 창을 닫습니다.

보기:

public View()
{
    InitializeComponent();
    ViewModel vm = new ViewModel (); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if (vm.CloseAction == null)
        vm.CloseAction = new Action(() => this.Close());
}

이 게시물이 오래된 게시물이라는 것을 압니다. 아마 아무도 여기까지 스크롤하지 않을 것입니다. 저는 그렇지 않다는 것을 압니다.그래서, 몇 시간 동안 다른 것들을 시도한 후에, 저는 이 블로그를 발견했고, 그 친구는 그것을 죽였습니다.이것을 하는 가장 간단한 방법은, 시도해보고, 그것은 매력적으로 작동합니다.

블로그

뷰 모델에서:

...

public bool CanClose { get; set; }

private RelayCommand closeCommand;
public ICommand CloseCommand
{
    get
    {
        if(closeCommand == null)
        (
            closeCommand = new RelayCommand(param => Close(), param => CanClose);
        )
    }
}

public void Close()
{
    this.Close();
}

...

작업 속성을 View 모델에 추가하지만 View의 코드 뒤에 있는 파일에서 정의합니다.그러면 뷰를 가리키는 뷰 모델에서 참조를 동적으로 정의할 수 있습니다.

View Model에서는 다음을 추가합니다.

public Action CloseAction { get; set; }

View에서는 다음과 같이 정의합니다.

public View()
{
    InitializeComponent() // this draws the View
    ViewModel vm = new ViewModel(); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if ( vm.CloseAction == null )
        vm.CloseAction = new Action(() => this.Close());
}

다음은 이벤트 대신 MVVM Light Messenger를 사용한 간단한 예입니다.버튼을 클릭하면 뷰 모델이 닫기 메시지를 보냅니다.

    public MainViewModel()
    {
        QuitCommand = new RelayCommand(ExecuteQuitCommand);
    }

    public RelayCommand QuitCommand { get; private set; }

    private void ExecuteQuitCommand() 
    {
        Messenger.Default.Send<CloseMessage>(new CloseMessage());
    }

그런 다음 창 뒤의 코드로 수신됩니다.

    public Main()
    {   
        InitializeComponent();
        Messenger.Default.Register<CloseMessage>(this, HandleCloseMessage);
    }

    private void HandleCloseMessage(CloseMessage closeMessage)
    {
        Close();
    }

이와 같이 View Model에서 새 Event 핸들러를 생성할 수 있습니다.

public event EventHandler RequestClose;

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

그런 다음 종료 명령에 대한 릴레이 명령을 정의합니다.

private RelayCommand _CloseCommand;
    public ICommand CloseCommand
    {
        get
        {
            if(this._CloseCommand==null)
                this._CloseCommand=new RelayCommand(CloseClick);
            return this._CloseCommand;
        }
    }

    private void CloseClick(object obj)
    {
        OnRequestClose();
    }

그러면 XAML 파일 세트에서

<Button Command="{Binding CloseCommand}" />

xaml.cs 파일에서 DataContext를 설정하고 만든 이벤트에 가입합니다.

public partial class MainWindow : Window
{
    private ViewModel mainViewModel = null;
    public MainWindow()
    {
        InitializeComponent();
        mainViewModel = new ViewModel();
        this.DataContext = mainViewModel;
        mainViewModel.RequestClose += delegate(object sender, EventArgs args) { this.Close(); };
    }
}

제가 제안하는 방법은 ViewModel에서 이벤트를 선언하고 아래와 같이 Blend InvokeMethodAction을 사용하는 것입니다.

샘플 뷰 모델

public class MainWindowViewModel : BindableBase, ICloseable
{
    public DelegateCommand SomeCommand { get; private set; }
    #region ICloseable Implementation
    public event EventHandler CloseRequested;        

    public void RaiseCloseNotification()
    {
        var handler = CloseRequested;
        if (handler != null)
        {
            handler.Invoke(this, EventArgs.Empty);
        }
    }
    #endregion

    public MainWindowViewModel()
    {
        SomeCommand = new DelegateCommand(() =>
        {
            //when you decide to close window
            RaiseCloseNotification();
        });
    }
}

I Closeable 인터페이스는 아래와 같으나 이 작업을 수행할 필요는 없습니다.ICloseable은 일반 뷰 서비스를 만드는 데 도움이 되므로 종속성 주입으로 뷰 및 뷰 모델을 구성하면 다음과 같이 할 수 있습니다.

internal interface ICloseable
{
    event EventHandler CloseRequested;
}

I closeable 사용

var viewModel = new MainWindowViewModel();
        // As service is generic and don't know whether it can request close event
        var window = new Window() { Content = new MainView() };
        var closeable = viewModel as ICloseable;
        if (closeable != null)
        {
            closeable.CloseRequested += (s, e) => window.Close();
        }

그리고 아래는 Xaml입니다. 인터페이스를 구현하지 않더라도 이 Xaml을 사용할 수 있습니다. CloseRquested를 올리려면 뷰 모델만 필요합니다.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFRx"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
xmlns:ViewModels="clr-namespace:WPFRx.ViewModels" x:Name="window" x:Class="WPFRx.MainWindow"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" 
d:DataContext="{d:DesignInstance {x:Type ViewModels:MainWindowViewModel}}">

<i:Interaction.Triggers>
    <i:EventTrigger SourceObject="{Binding Mode=OneWay}" EventName="CloseRequested" >
        <ei:CallMethodAction TargetObject="{Binding ElementName=window}" MethodName="Close"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

<Grid>
    <Button Content="Some Content" Command="{Binding SomeCommand}" Width="100" Height="25"/>
</Grid>

사용할 수 있습니다.MessengerMVVMLight 툴킷에서 다운로드할 수 있습니다.당신의ViewModel다음과 같은 메시지를 보냅니다.
Messenger.Default.Send(new NotificationMessage("Close"));
뒤에 코드에서 리고뒤있당윈코드서에후도그우신의는에, 그후▁then그 뒤에 있습니다.InitializeComponent과 같은

Messenger.Default.Register<NotificationMessage>(this, m=>{
    if(m.Notification == "Close") 
    {
        this.Close();
    }
   });

MVVMLight 툴킷에 대한 자세한 내용은 여기에서 확인할 수 있습니다: 코드플렉스의 MVVMLight 툴킷

MVVM에는 "모든 코드 뒤에 규칙이 없습니다"가 없으며 코드 뒤에 보기에서 메시지를 등록할 수 있습니다.

창을 서비스로 처리할 수 있습니다(예:UI 서비스) 및 인터페이스를 통해 모델을 보기 위해 다음과 같이 전달합니다.

public interface IMainWindowAccess
{
    void Close(bool result);
}

public class MainWindow : IMainWindowAccess
{
    // (...)
    public void Close(bool result)
    {
        DialogResult = result;
        Close();
    }
}

public class MainWindowViewModel
{
    private IMainWindowAccess access;

    public MainWindowViewModel(IMainWindowAccess access)
    {
        this.access = access;
    }

    public void DoClose()
    {
        access.Close(true);
    }
}

은 물리적으로 모델로 에 MVVM을 뷰 뷰 큰 입니다. 물리적으로 뷰가 뷰 모델로 전달되지만 후자는 여전히 전자에 대해 알지 못하고 일부만 보기 때문입니다.IMainWindowAccess이, 이을션다플로마으션하려이는이레경그우됩다어구니문것이이가제현는을하솔션루랫폼른루솔ing▁so▁a,▁to다됩▁implement▁be예▁it니▁only▁matter▁would▁for▁of▁we▁solution▁this▁wanted를▁platform▁if▁instance문가▁to▁migrate제▁other,것이구를 구현하는 것이 문제가 될 것입니다.IMainWindowAccess를 들어, 를들어적, 합한에예에 .Activity.

구현해야 할 이벤트(첨부/분리 등)보다 조금 더 단순해 보이지만 MVVM 패턴과 잘 일치하기 때문에 이벤트와는 다른 접근 방식(실제로는 매우 유사함)을 제안하기 위해 여기에 솔루션을 게시합니다.

간단합니다.Login - LoginViewModel에 대한 ViewModel 클래스를 만들 수 있습니다.LoginView Model 내에 var 대화상자 = 새 UserView()를 생성할 수 있습니다.명령 로그인 명령을 버튼으로 설정할 수 있습니다.

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding LoginCommand}" />

그리고.

<Button Name="btnCancel" IsDefault="True" Content="Login" Command="{Binding CancelCommand}" />

모델 클래스 보기:

public class LoginViewModel
{
    Window dialog;
    public bool ShowLogin()
    {
       dialog = new UserView();
       dialog.DataContext = this; // set up ViewModel into View
       if (dialog.ShowDialog() == true)
       {
         return true;
       }

       return false;
    }

    ICommand _loginCommand
    public ICommand LoginCommand
    {
        get
        {
            if (_loginCommand == null)
                _loginCommand = new RelayCommand(param => this.Login());

            return _loginCommand;
        }
    }

    public void CloseLoginView()
    {
            if (dialog != null)
          dialog.Close();
    }   

    public void Login()
    {
        if(CheckLogin()==true)
        {
            CloseLoginView();         
        }
        else
        {
          // write error message
        }
    }

    public bool CheckLogin()
    {
      // ... check login code
      return true;
    }
}

이것이 제가 꽤 간단하게 한 방법입니다.

YourWindow.xaml.cs

//In your constructor
public YourWindow()
{
    InitializeComponent();
    DataContext = new YourWindowViewModel(this);
}

YourWindowViewModel.cs

private YourWindow window;//so we can kill the window

//In your constructor
public YourWindowViewModel(YourWindow window)
{
    this.window = window;
}

//to close the window
public void CloseWindow()
{
    window.Close();
}

저는 당신이 선택한 답에 아무런 문제가 없다고 생각합니다. 저는 단지 이것이 그것을 하는 더 간단한 방법일 수도 있다고 생각했습니다!

MVVM WPF에서는 일반적으로 View를 사용자 컨트롤로 설계합니다.그리고 그것은 단지 당신이 그것을 어떻게 전시하기를 원하는지의 문제입니다.Window(윈도우)에 포함하려면 WindowService(윈도우 서비스) 클래스를 수행할 수 있습니다.

public class WindowService
{
   //...

   public void Show_window(object viewModel, int height, int width, string title)
   {
     var window = new Window
     {
       Content = viewModel,
       Title = title,
       Height = height,
       Width = width,
       WindowStartupLocation = WindowStartupLocation.CenterOwner,
       Owner = Application.Current.MainWindow,
       Style = (Style)Application.Current.FindResource("Window_style") //even style can be added
      };

      //If you own custom window style, then you can bind close/minimize/maxmize/restore buttons like this 
      window.CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, OnCloseWindow));
      window.CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, OnMaximizeWindow, OnCanResizeWindow));
      window.CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, OnMinimizeWindow, OnCanMinimizeWindow));
      window.CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, OnRestoreWindow, OnCanResizeWindow));
                  
      window.ShowDialog();
   }

   public void Close_window(object viewmodel)
   {
       //Close window
       foreach (Window item in Application.Current.Windows)
       {
          if (item.Content == viewmodel) item.Close();
       }
    }
}

내 접근 방식을 사용하는 것은 간단합니다.일반적으로 창에 문제가 발생하면 창을 닫습니다.그러면 해당 ViewModel에서 Close_window 메서드를 호출하면 됩니다. 이 메서드는 창에 표시되는 UserControl의 DataContext입니다.하단의 예를 살펴봅니다.

1.) 일부 View 모델에서 Window를 엽니다.

public class MyViewModel // ViewModel where you open window
{
   private readonly WindowService _windowservice // or inject/inherit from Base

   public MyViewModel()
   {
     _windowservice = new WindowService();
   }  

   private void Example_method()
   {
        //...Open window
        _windowservice.Show_window(new WindowViewModel(),100,100,"Test window");
   }
  
}

2.) 창이 이미 열려 있습니다. 이제 창을 닫으려고 합니다.

 public class WindowViewModel // ViewModel which is your Window content!
 {
     private readonly WindowService _windowservice // or inject/inherit from Base

     public MyViewModel()
     {
       _windowservice = new WindowService();
     }  

     private void Example_method()
     {
          //Close window
          _windowservice.Close(this); //Pass a reference of viewmodel to method
     }
    
  }

이 해결책은 다른 수용된 답들보다 훨씬 덜 우아하지만, 저에게는 효과가 있습니다.프로젝트에서 널리 사용하고 있기 때문에 아직까지는 문제가 없습니다.하지만 누군가가 와서 "그것은 MVVM 원칙 위반이다"라고 말할 것이라고 확신합니다.

다음 코드를 사용하여 현재 창을 닫을 수 있습니다.

Application.Current.Windows[0].Close();

시스템.환경.종료(0). 뷰 모델에서 작동합니다.

언급URL : https://stackoverflow.com/questions/16172462/close-window-from-viewmodel

반응형