MVP Sample for Winform

MVP Sample for Winform

이철우

MVC 에서 개선한 것.

  • C# Winform의 DataBinding 과 INotifyPropertyChanged 를 이용하여
  • Model 과 View 에서
  • DataChangedEvent 를 뺐다.
  1. 먼저 Winform 프로젝트(.Net 7)를 만든다.
    0-1. 프로젝트 속성에서 'Console Application’을 선택한다.
    0-2. Form1 디자인에서 TextBoxData, ButtonReset, ButtonIncrease 를 추가한다.

  2. IView.cs

    public interface IView
    {
        TextBox TextBoxData { get; }

        event EventHandler<EventArgs>? ResetPressed;
        event EventHandler<EventArgs>? IncreasePressed;
    }
  1. Model.cs
    public class Model : INotifyPropertyChanged
    {
        public Model() { }
        public int Data
        {
            get => _data;
            set
            {
                if (_data != value)
                {
                    _data = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Data)));
                    Console.WriteLine(ToString());
                }
            }
        }
        private int _data = 0;

        public void Reset() => Data = 0;
        public void Increase() => Data++;
        public void Set(int data) => Data = data;

        public override string ToString() => $"Data:{Data}";

        public event PropertyChangedEventHandler? PropertyChanged;
    }

  1. Presenter.cs
    public class Presenter
    {
        public Model Model { get; private set; }
        public IView View { get; private set; }

        public Presenter(Model model, IView view)
        {
            Model = model;
            View = view;

            View.ResetPressed += View_ResetPressed;
            View.IncreasePressed += View_IncreasePressed;

            var binding = new BindingSource
            {
                DataSource = Model
            };
            View.TextBoxData.DataBindings.Add(new Binding("Text", binding, "Data", true, DataSourceUpdateMode.OnPropertyChanged));
        }

        private void View_ResetPressed(object? sender, EventArgs e)
        {
            Model.Reset();
        }
        private void View_IncreasePressed(object? sender, EventArgs e)
        {
            Model.Increase();
        }
    }
  1. IView 상속받은 Form1.cs
    public partial class Form1 : Form, IView
    {
        public Form1()
        {
            InitializeComponent();
        }

        TextBox IView.TextBoxData => TextBoxData;

        public event EventHandler<EventArgs>? ResetPressed;
        public event EventHandler<EventArgs>? IncreasePressed;

        private void ButtonReset_Click(object sender, EventArgs e)
        {
            ResetPressed?.Invoke(this, new EventArgs());
        }

        private void ButtonIncrease_Click(object sender, EventArgs e)
        {
            IncreasePressed?.Invoke(this, new EventArgs());
        }
    }

  1. Program.cs
    internal static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // To customize application configuration such as set high DPI settings or default font,
            // see https://aka.ms/applicationconfiguration.
            ApplicationConfiguration.Initialize();

            #region MVP Sample for Winform.
            var view = new Form1();
            var model = new Model();
            _ = new Presenter(model, view);
            #endregion

            Application.Run(view);
        }
    }
3 Likes

글 잘 읽었습니다. 혹시, IView Interface로 구현한 UserControl끼리, 데이터를 주고 받거나 이벤트를 전송하는 방법에 대해서 말씀 부탁드려도 될까요? 예를 들어, 혹시 HTS를 사용하셨다면, 실시간 잔고에 있는 한 종목을 클릭하면 그 종목에 대한 차트 페이지에서도 자동으로 그 종목의 차트로 바꿔주는 것입니다. 미리 감사드립니다.

1 Like

[1] 클래스 [실시간 잔고]에서 이벤트 [한 종목을 클릭]를 만듭니다. 이벤트 인수로 [그 종목]을 보냅니다.

[2] 클래스 [차트 페이지]에서 [1]에서 만든 [한 종목을 클릭] 이벤트를 수신합니다. 인수로 받은 [그 종목]의 차트로 바꿉니다.

1 Like

대개의 증권사 HTS는 예전 기술이라 .Net으로 넘어가지 못하고 있습니다.
RESTful API로 넘어간 곳은 한투, 디비 정도인 것으로 알고있습니다.

.Net이 가능하다면, Winform MVVM 추천합니다.

1 Like

차트 페이지가 열려있다면, 이미 그 종목의 차트를 보여주고 있는 상태인데, 차트를 바꿀 필요가 있을까요?

1 Like

죄송합니다 제가 설명이 부족했던 것 같습니다. 예를 들어,
보유 중인 종목 UserControl에서 종목 A, B가 있을 때 (예를 들어, GridView를 생각해볼 수 있을 것 같습니다)
현재 차트 UserControl이 A에 대한 차트를 보여주고 있을 때, B종목을 클릭하면 차트도 B종목으로 동기화가 되게 하기 위함이었습니다.

1 Like
interface IChartItemChangedPublisher
{
   event EventHandler<ChartItem> ChartItemChanged {get; }
}

partial class ItemsControl : IChartItemChangedPublisher
{
   public event EventHandler<ChartItem> ChartItemChanged {get; } = delegate { };
   // ...
   ChartItem? _currentItem;
   void OnItemSelected(object? sender, EventArgs e)
   {
      ChartItem item = // ...
      if (_currenItem != item)
      {
         _currentItem = item;
         ChartItemChanged.Invoke(item);
      }
   }
}

partial class ChartControl : IDisposable
{
   public ChartControl(IChartItemChangedPublisher publisher)
   {
      // IDisposable 을 구현하지 않을 때
      // publisher.ChartItemChanged -= OnChartItemChanged;
      publisher.ChartItemChanged += OnChartItemChanged;   
   }

   void OnChartItemChanged(object? sender, ChartItem item)
   {
      // ...
   }
   public void Dispose() => 
      publisher.ChartItemChanged -= OnChartItemChanged;
}
1 Like