programing

MVVM을 사용한WPF 대화상자 처리

mailnote 2023. 4. 16. 15:30
반응형

MVVM을 사용한WPF 대화상자 처리

WPF의 MVVM 패턴에서는 대화상자의 처리가 보다 복잡한 조작 중 하나입니다.뷰 모델은 뷰에 대해 아무것도 모르기 때문에 대화 상자 통신은 흥미로울 수 있습니다.내가 폭로할 수 있는 건ICommand보기가 호출할 때 대화 상자가 나타날 수 있습니다.

대화 상자의 결과를 처리하는 좋은 방법을 아는 사람이 있습니까?'와 같은 대화창에 .MessageBox.

이를 위한 방법 중 하나는 뷰 모델에서 대화상자가 필요할 때 뷰가 구독하는 이벤트를 생성하는 것입니다.

public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;

이것은 괜찮지만, 보기에는 코드가 필요하기 때문에 피하고 싶은 것입니다.

1990년대 모달 대화 상자를 없애고 대신 오버레이(캔버스+절대 위치 설정)로 컨트롤을 구현하고 VM의 부울에 가시성을 결합할 것을 제안합니다.Ajax 타입 컨트롤에 가깝습니다.

이것은 매우 유용합니다.

<BooleanToVisibilityConverter x:Key="booltoVis" />

예를 들어 다음과 같습니다.

<my:ErrorControl Visibility="{Binding Path=ThereWasAnError, Mode=TwoWay, Converter={StaticResource booltoVis}, UpdateSourceTrigger=PropertyChanged}"/>

사용자 컨트롤로 구현한 방법은 다음과 같습니다.'x'를 클릭하면 사용자 제어 코드 뒤에 있는 코드로 컨트롤이 닫힙니다. (내 뷰는 .exe에 있고 View Models는 dll에 있기 때문에 UI를 조작하는 코드에 대해서는 나쁘지 않습니다.)

Wpf 대화 상자

편집: 10년 이상 지난 지금, 중개자나 다른 메시지 패턴을 사용하는 것은 매우 나쁜 생각이라는 것을 알 수 있습니다.그렇게 하지 말고 Jeffrey의 답변이나 IDalog Service를 뷰 모델에 삽입하기만 하면 됩니다.


당신은 이 일에 중재자를 이용해야 합니다.Mediator는 일부 구현에서 Messenger라고도 하는 일반적인 설계 패턴입니다.이는 Register/Notify 유형의 패러다임으로 View Model과 Views가 저커플링 메시징 메카니즘을 통해 통신할 수 있도록 합니다.

Google WPF Themptors 그룹을 확인하고 Mediator를 검색하십시오.당신은 그 대답에 매우 만족할 것이다.

단, 다음과 같이 시작할 수 있습니다.

http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/

맛있게 드세요!

편집: MVVM Light Toolkit에서 이 문제에 대한 답을 볼 수 있습니다.

http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338

정상적인 MVVM 대화상자는 다음과 같습니다.

  1. XAML만으로 선언됩니다.
  2. 데이터 바인딩에서 모든 동작을 가져옵니다.

유감스럽게도 WPF는 이러한 기능을 제공하지 않습니다.하려면 , 「」에의 합니다.ShowDialog()클래스는 수 에 Window 클래스는 XAML로 수 DataContext.

컨트롤을 작성하여 데이터 을 XAML로 .Window및 대화 상자를 표시하거나 숨깁니다.다음 URL에서 찾을 수 있습니다.http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

ViewModel을 쉽게 변경할 수 있으며 이벤트나 메시지가 필요하지 않습니다.기본 콜은 다음과 같습니다.

<dialog:Dialog Content="{Binding Path=DialogViewModel}" Showing="True" />

, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 이런 을 넣는 게 것 같아요.Showing제 기사에서 설명하고 있습니다.츠키노

MVVM과의 대화에서는 이 방법을 사용합니다.

내가 지금 해야 할 일은 내 뷰 모델에서 다음을 호출하는 것이다.

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);

현재 사용하고 있는 솔루션은 플랫폼 고유의 문제에서 완전히 추상화되어 있어 고객이 언급한 대부분의 문제를 해결하고 재사용할 수중에 재사용할 수 있습니다.또한 ICMand를 구현하는 DelegateCommands에 대해서만 코드 비하인드 바인딩을 사용하지 않았습니다.대화상자는 기본적으로 View(보기)입니다. ViewModel은 자체 ViewModel을 가지며 메인 화면의 ViewModel에서 표시되지만 DelagateCommand 바인딩을 통해 UI에서 트리거됩니다.

MVM 및 Silverlight 4를 사용한 모든 Silverlight 4 솔루션 대화상자는 여기를 참조하십시오.

MVVM을 배울 때(아직도 학습 중) 이 컨셉에 대해 한동안 고민했습니다.내가 결정한 것, 그리고 다른 사람들은 이미 결정했다고 생각하지만 명확하지 않은 것은 다음과 같다.

View Model은 대화 상자의 표시 방법을 결정할 필요가 없기 때문에 직접 대화 상자를 호출해서는 안 된다고 생각했습니다.그래서 어떻게 하면 MVP 때처럼 메시지를 전달할 수 있을까를 고민하기 시작했다(예: View).Show Save File Dialog()).하지만 저는 이것이 잘못된 접근이라고 생각합니다.

View Model이 직접 대화상자를 호출해도 됩니다.단, ViewModel을 테스트하는 경우 테스트 중에 대화상자가 팝업되거나 (실제로 테스트한 적이 없음) 모두 실패하게 됩니다.

따라서 테스트 중에 대화상자의 "테스트" 버전을 사용해야 합니다.즉, 대화 상자에 대해 인터페이스를 만들고 대화 상자 응답을 목아웃하거나 기본 동작을 갖는 테스트 모크를 만들어야 합니다.

컨텍스트에 따라 올바른 버전을 제공하도록 설정할 수 있는 서비스 로케이터 또는 IoC를 이미 사용하고 있어야 합니다.

이 방법을 사용하면 ViewModel은 여전히 테스트 가능하며 대화 상자를 어떻게 시뮬레이션하느냐에 따라 동작을 제어할 수 있습니다.

이게 도움이 됐으면 좋겠다.

여기에는 1)대화상자 서비스(간단함, 깔끔함)와 2)뷰 어시스트의 2가지 좋은 방법이 있습니다.View Assisted는 몇 가지 깔끔한 기능을 제공하지만 일반적으로는 그럴 가치가 없습니다.

대화 서비스

a) 컨스트럭터 또는 일부 종속 컨테이너를 경유하는 대화 상자 서비스 인터페이스:

interface IDialogService { Task ShowDialogAsync(DialogViewModel dlgVm); }

b) IDialog Service를 구현하려면 창을 열고(또는 활성 창에 일부 컨트롤을 삽입), 지정된 dlgVm 유형의 이름에 대응하는 보기를 생성해야 합니다(컨테이너 등록 또는 규칙 또는 DataTemplates 유형이 연관된 ContentPresenter 사용).ShowDialogAsync는 TaskCompletion을 생성해야 합니다.송신원 및 반환.태스크 프로펠러.DialogViewModel 클래스 자체에는 종료할 때 파생 클래스에서 호출할 수 있는 이벤트가 필요하며 실제로 대화상자를 닫거나 숨기거나 TaskCompletion을 완료하기 위해 대화상자 뷰에서 볼 수 있습니다.원천.

b) 사용하기 위해서는 전화만 하면 됩니다.Dialog Service(대화상자 서비스)일부 DialogViewModel 파생 클래스의 인스턴스에서 ShowDialog(myDlgVm)를 표시합니다.반환 대기 후 대화 상자 VM에 추가한 속성을 보고 무슨 일이 발생했는지 확인합니다. 콜백도 필요하지 않습니다.

뷰 지원

뷰 모델에서 이벤트를 재생하는 뷰가 있습니다.이 모든 것을 Blend Behavior(혼합 동작)로 정리하여 코드 배후에 있는 코드와 자원 사용을 피할 수 있습니다(FMI, 스테로이드제의 Blendable Attached 속성을 확인하기 위한 "Behavior" 클래스 하위 클래스).이 작업은 각 뷰에서 수동으로 수행합니다.

a) 커스텀 페이로드(Dialog View Model 파생 클래스)를 사용하여 OpenXXXXDialogEvent를 만듭니다.

b) 뷰가 OnDataContextChanged 이벤트의 이벤트에 가입하도록 합니다.이전 값 !=이(가) null이고 Window의 Unloaded(언로드되지 않음) 이벤트에 있는 경우 숨기고 구독을 취소해야 합니다.

c) 이벤트가 발생하면 뷰에서 뷰를 열도록 합니다.이 뷰는 페이지상의 리소스에 있을 수 있습니다.또, 다른 장소(대화상자 서비스 어프로치 등)에서도 찾을 수 있습니다.

이 접근방식은 유연성은 높지만 사용하기 위해서는 더 많은 작업이 필요합니다.잘 안 써요.예를 들어 뷰를 탭 안에 물리적으로 배치할 수 있는 장점이 있습니다.알고리즘을 사용하여 현재 사용자 컨트롤의 경계에 배치하거나 충분히 크지 않은 경우 충분한 크기의 컨테이너가 발견될 때까지 시각적 트리를 따라 이동했습니다.

이를 통해 대화 상자는 실제로 사용되는 장소에 가깝고, 현재 활동과 관련된 앱의 일부만 어둡게 표시되며, 사용자가 수동으로 대화 상자를 밀어낼 필요 없이 앱 내에서 이동할 수 있으며, 여러 개의 준모달 대화 상자는 서로 다른 탭이나 하위 보기에서 열 수 있습니다.

freezable 명령어 사용

<Grid>
        <Grid.DataContext>
            <WpfApplication1:ViewModel />
        </Grid.DataContext>


        <Button Content="Text">
            <Button.Command>
                <WpfApplication1:MessageBoxCommand YesCommand="{Binding MyViewModelCommand}" />
            </Button.Command>
        </Button>

</Grid>
public class MessageBoxCommand : Freezable, ICommand
{
    public static readonly DependencyProperty YesCommandProperty = DependencyProperty.Register(
        "YesCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty OKCommandProperty = DependencyProperty.Register(
        "OKCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty CancelCommandProperty = DependencyProperty.Register(
        "CancelCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty NoCommandProperty = DependencyProperty.Register(
        "NoCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
        "Message",
        typeof (string),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata("")
        );

    public static readonly DependencyProperty MessageBoxButtonsProperty = DependencyProperty.Register(
        "MessageBoxButtons",
        typeof(MessageBoxButton),
        typeof(MessageBoxCommand),
        new FrameworkPropertyMetadata(MessageBoxButton.OKCancel)
        );

    public ICommand YesCommand
    {
        get { return (ICommand) GetValue(YesCommandProperty); }
        set { SetValue(YesCommandProperty, value); }
    }

    public ICommand OKCommand
    {
        get { return (ICommand) GetValue(OKCommandProperty); }
        set { SetValue(OKCommandProperty, value); }
    }

    public ICommand CancelCommand
    {
        get { return (ICommand) GetValue(CancelCommandProperty); }
        set { SetValue(CancelCommandProperty, value); }
    }

    public ICommand NoCommand
    {
        get { return (ICommand) GetValue(NoCommandProperty); }
        set { SetValue(NoCommandProperty, value); }
    }

    public MessageBoxButton MessageBoxButtons
    {
        get { return (MessageBoxButton)GetValue(MessageBoxButtonsProperty); }
        set { SetValue(MessageBoxButtonsProperty, value); }
    }

    public string Message
    {
        get { return (string) GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    public void Execute(object parameter)
    {
        var messageBoxResult = MessageBox.Show(Message);
        switch (messageBoxResult)
        {
            case MessageBoxResult.OK:
                OKCommand.Execute(null);
                break;
            case MessageBoxResult.Yes:
                YesCommand.Execute(null);
                break;
            case MessageBoxResult.No:
                NoCommand.Execute(null);
                break;
            case MessageBoxResult.Cancel:
                if (CancelCommand != null) CancelCommand.Execute(null); //Cancel usually means do nothing ,so can be null
                break;

        }
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;


    protected override Freezable CreateInstanceCore()
    {
        throw new NotImplementedException();
    }
}

대화 상자의 처리는 뷰의 책임이며 뷰에는 이를 지원하는 코드가 있어야 한다고 생각합니다.

대화상자를 처리하도록 ViewModel - View 상호작용을 변경하면 ViewModel은 해당 구현에 종속됩니다.이 문제를 해결하는 가장 간단한 방법은 View가 작업을 수행하도록 하는 것입니다.대화 상자를 표시하는 경우 문제가 없지만 상태 표시줄 등에 상태 메시지가 표시될 수도 있습니다.

MVVM 패턴의 요점은 비즈니스 로직과 GUI를 분리하는 것이므로 비즈니스 계층(View Model)에서 GUI 로직을 혼합하여 대화 상자를 표시해서는 안 된다는 것입니다.

흥미로운 대안은 뷰(대화 상자)를 표시하는 책임이 있는 컨트롤러를 사용하는 것입니다.

동작은 WPF Application Framework(WAF; WPF 애플리케이션 프레임워크)에 나타나 있습니다.

VM에서 이벤트를 생성하고 뷰에서 이벤트를 구독하는 것이 어떨까요?이렇게 하면 응용 프로그램 로직과 보기가 분리되고 대화 상자에 하위 창을 사용할 수 있습니다.

View Model에서 메시지를 재생하는 동작을 구현했습니다.Laurent Bugnion 솔루션을 기반으로 하고 있지만, 뒤에 코드를 사용하지 않고 재사용이 가능하기 때문에 더욱 우아하다고 생각합니다.

WPF를 즉시 MVVM이 지원되는 것처럼 동작시키는 방법

뷰 모델에서 이벤트를 처리하는 코드가 뷰에 있을 수 있습니다.

이벤트/시나리오에 따라 모델이벤트를 표시하도록 서브스크라이브하는 이벤트트리거와 응답으로 호출하는1개 이상의 액션은 이벤트/시나리오에 따라 달라집니다.

저도 같은 상황이 되어 MessageBox를 디자이너의 보이지 않는 컨트롤로 포장했습니다.자세한 내용은 제 블로그에 있습니다.

http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

모든 모달 대화상자, 파일 브라우즈 제어 등에도 동일하게 확장할 수 있습니다.

표준 접근법

WPF에서 이 문제에 대처하는 데 수년을 소비한 후, WPF에서 대화상자를 구현하는 표준 방법을 마침내 알아냈다.이 접근방식의 장점은 다음과 같습니다.

  1. 깨끗한
  2. MVVM 설계 패턴을 위반하지 않음
  3. View Modal은 UI 라이브러리(Windows Base, Presentation Framework 등)를 참조하지 않습니다.
  4. 자동 테스트에 최적
  5. 대화 상자는 쉽게 교체할 수 있습니다.

그래서 열쇠가 뭐죠?DI + IOC 입니다.

작동 방식은 다음과 같습니다.MVVM Light를 사용하고 있지만 이 접근 방식은 다른 프레임워크로도 확장될 수 있습니다.

  1. 솔루션에 WPF 응용 프로그램 프로젝트를 추가합니다.이라고 불러주세요.
  2. ViewModal 클래스 라이브러리를 추가합니다.VM이라고 부릅니다.
  3. 앱이 VM 프로젝트를 참조합니다.VM 프로젝트는 App에 대해 아무것도 모릅니다.
  4. 프로젝트에 MVVM Light에 대한 NuGet 참조를 추가합니다.저는 요즘 MVVM Light Standard를 사용하고 있습니다만, 풀 프레임워크 버전도 괜찮습니다.
  5. VM 프로젝트에 인터페이스 IDalogService 추가:

    public interface IDialogService
    {
      void ShowMessage(string msg, bool isError);
      bool AskBooleanQuestion(string msg);
      string AskStringQuestion(string msg, string default_value);
    
      string ShowOpen(string filter, string initDir = "", string title = "");
      string ShowSave(string filter, string initDir = "", string title = "", string fileName = "");
      string ShowFolder(string initDir = "");
    
      bool ShowSettings();
    }
    
  6. 「」을 합니다.IDialogService해 주세요.ViewModelLocator단, 등록부분은 View레이어에서 실행할 수 있도록 남겨둡니다.이것이 열쇠입니다.:

    public static IDialogService DialogService => SimpleIoc.Default.GetInstance<IDialogService>();
    
  7. App 프로젝트에서 이 인터페이스의 구현을 추가합니다.

    public class DialogPresenter : IDialogService
    {
        private static OpenFileDialog dlgOpen = new OpenFileDialog();
        private static SaveFileDialog dlgSave = new SaveFileDialog();
        private static FolderBrowserDialog dlgFolder = new FolderBrowserDialog();
    
        /// <summary>
        /// Displays a simple Information or Error message to the user.
        /// </summary>
        /// <param name="msg">String text that is to be displayed in the MessageBox</param>
        /// <param name="isError">If true, Error icon is displayed. If false, Information icon is displayed.</param>
        public void ShowMessage(string msg, bool isError)
        {
                if(isError)
                        System.Windows.MessageBox.Show(msg, "Your Project Title", MessageBoxButton.OK, MessageBoxImage.Error);
                else
                        System.Windows.MessageBox.Show(msg, "Your Project Title", MessageBoxButton.OK, MessageBoxImage.Information);
        }
    
        /// <summary>
        /// Displays a Yes/No MessageBox.Returns true if user clicks Yes, otherwise false.
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool AskBooleanQuestion(string msg)
        {
                var Result = System.Windows.MessageBox.Show(msg, "Your Project Title", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes;
                return Result;
        }
    
        /// <summary>
        /// Displays Save dialog. User can specify file filter, initial directory and dialog title. Returns full path of the selected file if
        /// user clicks Save button. Returns null if user clicks Cancel button.
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="initDir"></param>
        /// <param name="title"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public string ShowSave(string filter, string initDir = "", string title = "", string fileName = "")
        {
                if (!string.IsNullOrEmpty(title))
                        dlgSave.Title = title;
                else
                        dlgSave.Title = "Save";
    
                if (!string.IsNullOrEmpty(fileName))
                        dlgSave.FileName = fileName;
                else
                        dlgSave.FileName = "";
    
                dlgSave.Filter = filter;
                if (!string.IsNullOrEmpty(initDir))
                        dlgSave.InitialDirectory = initDir;
    
                if (dlgSave.ShowDialog() == DialogResult.OK)
                        return dlgSave.FileName;
                else
                        return null;
        }
    
    
        public string ShowFolder(string initDir = "")
        {
                if (!string.IsNullOrEmpty(initDir))
                        dlgFolder.SelectedPath = initDir;
    
                if (dlgFolder.ShowDialog() == DialogResult.OK)
                        return dlgFolder.SelectedPath;
                else
                        return null;
        }
    
    
        /// <summary>
        /// Displays Open dialog. User can specify file filter, initial directory and dialog title. Returns full path of the selected file if
        /// user clicks Open button. Returns null if user clicks Cancel button.
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="initDir"></param>
        /// <param name="title"></param>
        /// <returns></returns>
        public string ShowOpen(string filter, string initDir = "", string title = "")
        {
                if (!string.IsNullOrEmpty(title))
                        dlgOpen.Title = title;
                else
                        dlgOpen.Title = "Open";
    
                dlgOpen.Multiselect = false;
                dlgOpen.Filter = filter;
                if (!string.IsNullOrEmpty(initDir))
                        dlgOpen.InitialDirectory = initDir;
    
                if (dlgOpen.ShowDialog() == DialogResult.OK)
                        return dlgOpen.FileName;
                else
                        return null;
        }
    
        /// <summary>
        /// Shows Settings dialog.
        /// </summary>
        /// <returns>true if User clicks OK button, otherwise false.</returns>
        public bool ShowSettings()
        {
                var w = new SettingsWindow();
                MakeChild(w); //Show this dialog as child of Microsoft Word window.
                var Result = w.ShowDialog().Value;
                return Result;
        }
    
        /// <summary>
        /// Prompts user for a single value input. First parameter specifies the message to be displayed in the dialog 
        /// and the second string specifies the default value to be displayed in the input box.
        /// </summary>
        /// <param name="m"></param>
        public string AskStringQuestion(string msg, string default_value)
        {
                string Result = null;
    
                InputBox w = new InputBox();
                MakeChild(w);
                if (w.ShowDialog(msg, default_value).Value)
                        Result = w.Value;
    
                return Result;
        }
    
        /// <summary>
        /// Sets Word window as parent of the specified window.
        /// </summary>
        /// <param name="w"></param>
        private static void MakeChild(System.Windows.Window w)
        {
                IntPtr HWND = Process.GetCurrentProcess().MainWindowHandle;
                var helper = new WindowInteropHelper(w) { Owner = HWND };
        }
    }
    
  8. 중는 범용 「」 「」 「」)이지만,ShowMessage,AskBooleanQuestion는 이 하며 커스텀을 Windows. 같은 방법으로 더 많은 사용자 지정 창을 추가할 수 있습니다.중요한 것은 UI별 요소를 View 계층에 유지하고 VM 계층에서 POCO를 사용하여 반환된 데이터를 노출하는 것입니다.
  9. 이 클래스를 사용하여 View레이어에서 인터페이스를 IoC 등록합니다.은 메인의 생성자(뒤로)에서할 수 .InitializeComponent() : 디세이블화):

    SimpleIoc.Default.Register<IDialogService, DialogPresenter>();
    
  10. 그렇지.이제 VM 계층과 View 계층 모두에서 모든 대화상자 기능에 액세스할 수 있습니다.VM 계층은 다음과 같은 기능을 호출할 수 있습니다.

    var NoTrump = ViewModelLocator.DialogService.AskBooleanQuestion("Really stop the trade war???", "");
    
  11. 깨끗해 보이시죠?VM 계층은 UI 계층이 사용자에게 예/아니오 질문을 제공하는 방법에 대해 전혀 알지 못하며 대화상자에서 반환된 결과를 계속 사용할 수 있습니다.

기타 무료 혜택

  1. 단위 맞춤 할수.IDialogService테스트 프로젝트에서 해당 클래스를 IoC에서 생성자 테스트 클래스에 등록합니다.
  2. ', '가져오다'와요.Microsoft.Win32[열기] 대화상자와 [저장]대화상자에 액세스 합니다.이러한 대화상자의 WinForms 버전도 있고 다른 사용자가 자신의 버전을 만들고 싶어할 수 있기 때문에 생략했습니다., 「」, 「ID」, 「ID」, 「에되고 있는 ID도 해 주세요.DialogPresenter는 내 는내창 ((((((((((((((((((((:SettingsWindow을 제공해야 합니다 인터페이스와 구현 모두에서 삭제하거나 자체 창을 제공해야 합니다.
  3. 실행하는 의 VM을 합니다.DispatcherHelper.Initialize()애플리케이션 라이프 사이클의 초기 단계입니다.
  4. DialogPresenter레이어에 된 다른 은 View Modal View에 .ViewModelLocator그런 다음 해당 유형의 공용 정적 속성이 View 계층에 노출되어야 합니다.다음과 같이 합니다.

    public static SettingsVM Settings => SimpleIoc.Default.GetInstance<SettingsVM>();
    
  5. 대부분의 경우 대화상자에는 DataContext 바인딩이나 설정 등에 대한 코드 배후에 포함되지 않아야 합니다.생성자 매개 변수로 전달하지 마십시오. XAML은 다음과 같이 모든 작업을 수행할 수 있습니다.

    <Window x:Class="YourViewNamespace.SettingsWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:local="clr-namespace:YourViewProject"
      xmlns:vm="clr-namespace:YourVMProject;assembly=YourVMProject"
      DataContext="{x:Static vm:ViewModelLocator.Settings}"
      d:DataContext="{d:DesignInstance Type=vm:SettingsVM}" />
    
  6. ★★DataContext인텔리센스, 자동완성 등 디자인 타임의 모든 이점을 제공합니다.

그게 모두에게 도움이 됐으면 좋겠어요.

이 질문에 대한 답변에서 설명한 대로 내 창 로더를 굴렸습니다.

응용 프로그램에서 여러 WPF 보기 관리

Karl Shifflett은 서비스 접근법과 Prism Interaction Request 접근 방식을 사용하여 대화 상자를 표시하는 샘플 애플리케이션을 개발했습니다.

서비스 접근법이 마음에 듭니다.유연성이 떨어지기 때문에 사용자가 고장날 가능성이 낮습니다.또한 어플리케이션(MessageBox)의 WinForms 부분과도 일치합니다.표시) 단, 다양한 대화상자를 표시할 예정이라면 Interaction Request를 사용하는 것이 좋습니다.

http://karlshifflett.wordpress.com/2010/11/07/in-the-box-ndash-mvvm-training/

오래된 질문인 것은 알지만, 이 검색을 해보니 관련된 질문이 많이 나오지만, 명확한 답변을 찾을 수 없었습니다.그래서 제가 직접 대화상자/메시지박스/팝인을 구현하고 공유합니다!
「MVVM 프루프」라고 생각하고, 심플하고 적절한 것을 목표로 하고 있습니다만, WPF는 처음이기 때문에, 코멘트나 풀 리퀘스트도 자유롭게 해 주세요.

https://github.com/Plasma-Paris/Plasma.WpfUtils

다음과 같이 사용할 수 있습니다.

public RelayCommand YesNoMessageBoxCommand { get; private set; }
async void YesNoMessageBox()
{
    var result = await _Service.ShowMessage("This is the content of the message box", "This is the title", System.Windows.MessageBoxButton.YesNo);
    if (result == System.Windows.MessageBoxResult.Yes)
        // [...]
}

또는 보다 정교한 팝인을 원하는 경우 다음과 같이 하십시오.

var result = await _Service.ShowCustomMessageBox(new MyMessageBoxViewModel { /* What you want */ });

그리고 그것은 다음과 같은 것을 보여준다.

2

저는 이 주제에 대해 상당히 포괄적인 기사를 썼고 MVVM Dialogs용 팝업 라이브러리를 개발했습니다.MVVM을 엄격하게 준수할 수 있을 뿐만 아니라 적절하게 구현될 경우 매우 깨끗하며, MVVM 자체를 준수하지 않는 타사 라이브러리로 쉽게 확장할 수 있습니다.

https://www.codeproject.com/Articles/820324/Implementing-Dialog-Boxes-in-MVVM

작업이나 대화 상자의 모델이 어떻게 보여야 하는지 물어볼 때 비슷한 문제를 고민하고 있었습니다.

현재의 솔루션은 다음과 같습니다.

public class SelectionTaskModel<TChoosable> : ViewModel
    where TChoosable : ViewModel
{
    public SelectionTaskModel(ICollection<TChoosable> choices);
    public ReadOnlyCollection<TChoosable> Choices { get; }
    public void Choose(TChoosable choosen);
    public void Abort();
}

뷰 모델은 사용자 입력이 필요하다고 판단되면 다음 인스턴스를 가져옵니다.SelectionTaskModel사용자가 선택할 수 있습니다.하는 뷰를 이는 적절한 에 「이 뷰」를 합니다.이 뷰는 적절한 타이밍에 호출됩니다.Choose()사용자의 선택에 따라 기능합니다.

나는 같은 문제로 고생했다.View와 View Model 간에 상호 통신하는 방법을 생각해냈습니다.ViewModel에서 View로 메시지 전송을 시작하여 메시지 상자를 표시하도록 지시할 수 있습니다. 그러면 결과가 보고됩니다.그러면 View Model이 View에서 반환된 결과에 응답할 수 있습니다.

블로그에서 시연하고 있습니다.

미안하지만, 나도 껴야 해.저는 프리즘을 찾기 전에 몇 가지 제안된 해결책을 검토했습니다.Wpf.Prism 프로젝트의 인터랙티브 네임스페이스.상호 작용 요청 및 팝업 창 액션을 사용하여 사용자 정의 창을 롤링할 수도 있고 필요에 따라 알림 및 확인 팝업에 기본 제공되어 있습니다.이들은 진정한 창을 만들고 이와 같이 관리됩니다.대화 상자에서 필요한 종속성을 가진 컨텍스트 개체를 전달할 수 있습니다.이 솔루션은 제가 발견한 이후 제 직장에서 사용하고 있습니다.여기 수많은 선임병들이 있는데 아무도 더 나은 방법을 생각해내지 못했어.이전 솔루션은 대화 서비스를 오버레이로 만들고 프레젠터 클래스를 사용하여 이를 실현하는 것이었지만, 모든 대화 뷰 모델 등에 대해 공장을 만들어야 했습니다.

이것은 사소한 것이 아니라 매우 복잡하지도 않다.또, 프리즘에 짜넣어져 있기 때문에, IMHO 의 베스트 프랙티스(또는 베스트 프랙티스)입니다.

내 2센트!

가장 간단한 방법: Hanuman Institute를 사용합니다.MvvmDialogs 라이브러리

설명서에 따르면 UI에서 완전히 분리하여 이렇게 아름답게 사용할 수 있습니다.

var presetName = await dialogService.ShowSavePresetViewAsync(this);

편집: 네, 이것이 올바른 MVVM 접근법이 아니라는 데 동의합니다.블라인드 메이스가 제안하는 것과 유사한 방법을 사용하고 있습니다.

이렇게 할 수 있는 방법 중 하나는

기본 뷰 모델(모달 열기)에서 다음을 수행합니다.

void OpenModal()
{
    ModalWindowViewModel mwvm = new ModalWindowViewModel();
    Window mw = new Window();
    mw.content = mwvm;
    mw.ShowDialog()
    if(mw.DialogResult == true)
    { 
        // Your Code, you can access property in mwvm if you need.
    }
}

모달 창 뷰/뷰 모델:

XAML:

<Button Name="okButton" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">OK</Button>
<Button Margin="2" VerticalAlignment="Center" Name="cancelButton" IsCancel="True">Cancel</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; }

또는 WPF MVVM: 창을 닫는 방법

언급URL : https://stackoverflow.com/questions/454868/handling-dialogs-in-wpf-with-mvvm

반응형