'delegate'에 해당되는 글 2건

  1. 2023.03.29 [C#] Form Close에 따른 Disposed Exception
  2. 2020.06.20 [C#] delegate, 폼 간의 DATA 공유 2

회사에서 우리팀의 Windows Application 상용 프로그램을 만들어야 하는 이슈가 발생했다.

논의 끝에 VS 기반의 C#으로 기능을 구현하기로 하였고

Windows Application 개발 경험(개인 프로젝트인데.....;;;)이 있는 내가 설계부터 구현, 테스트까지 1인 프로젝트를 맡게 되었다.


나 역시도 C#이 주종목이 아니기에 무한한 지식의 조력자(Google-감사!)와 함께 진행하는 것으로 

내 프로그램의 모든 기능들은 C# 프로그래밍의 정석으로 만들어 지는 것이 아니다. 

그저 같은 기능을 구현함에 있어 수많은 구현 방식 중에 내 경험 및 지식에 빗대어 가장 유연하게 동작할 수 있는 방법을 채택하여 재조립 할 뿐.

 

때문에 구현하는 중간중간 다양한 버그 및 오류에 부딪친다.

 

이번 Exception Case는 기존 개인 프로젝트(L-ATS)를 진행하면서는 발생하지 않았던 문제였었는데 이번에 겪게되어 현재 내가 설계한 프로그램의 성격에 알맞는 방식으로 처리한 내용을 기록해 본다.

 

C#이나 WFP가 주종목이신 분들은...아주 사소한 문제일거 같다...


Ocurred Exception

System.ObjectDisposedException: '삭제된 개체에 액세스할 수 없습니다.'

Exception 발생 Case

  • Parent Form과 Child Form이 존재
  • Parent Form에서 Child Form.show()를 호출하여 Form을 띄우고 Child Form에 입력한 Data를 Parent Form에서 받아서 처리 (Delegate Event 사용)     

2020.06.20 - [C#] - [C#] delegate, 폼 간의 DATA 공유

 

[C#] delegate, 폼 간의 DATA 공유

Trading 시스템을 내가 아닌 제 3자의 사용자적 입장에서 사용하도록 시뮬레이션 해 보았을 때 자식 Form을 새로 띄워서 값을 입력 받거나 확인할 수 있게 하는 작업이 많이 필요하단 것을 알게 되

brandon-dev.tistory.com

  • Child Form에서 Data 입력 후 [ 확인 ] 시, Form Close() 후, 해당 Parent Form에서 Child Form을 다시 show() 할 때 발생

Form.show() 호출 시 ObjectDisposedException 발생

Child Form에서의 Close() 함수 호출에 의해 완전 삭제된 Child Form의 객체를 다시 show() 호출로 로딩하려고 하니 이미 삭제된 객체를 불러올 수 없다는 말이다.(인것 같다...)

Child Form 내부에서 self로 Close()를 하게되면 해당 객체를 생성한 Parent Form에서 객체 삭제를 하지 않아도 자동으로 삭제 된다는 것일까...?

 

사실 이 Disposed Exception은 비단 Form에 한정되어 나타나는 현상은 아니다. 

WinForm의 어떠한 객체라도 삭제된 후 접근하려 할 경우 같은 현상이 나타날테니 말이다. 

때문에 이 Exception을 해결하는 방법은 아주 다양하고 상황에 따라 합리적인 예시들이 많이 있다. 


내가 만들고 있는 프로그램의 Child Form의 역할은 

프로그램을 운용하기 위한 기본 설정 값들을 사용자에게 입력 받아 Parent Form으로 전달하는 역할을 한다.

쉽게 프로그램의 설정 POP-UP이라고 생각하면 된다. 

 

나는 Child Form의 [ FormClosing() ] 이벤트에 아래 코드를 추가하는 방식을 택했다.

private void micSetting_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = true;
    this.Hide();
}

e.Cancel = true

FormClosing 작업을 취소하겠다는 것

this.Hide()

Form을 숨기겠다는 것

 

따라서 나는 분명 Child Form을 닫는 this.Close()를 호출하였지만 Form이 닫히는 과정(Form Closing)에서 Form이 닫히는 것을 취소하고 Form을 안보이도록 숨기겠다(Hide)는 뜻이다. 

 

여기서 중요한 점은.

Form을 사용자가 보지 못하게끔 숨기기만 하는 것으로 (사용자 입장에서는 Form이 꺼진것처럼 보이지만...)

이전에 Child Form에 입력한 값이 그대로 보인다는 것이다. Form을 숨기기만 하고 다시 보여주는 것이니 당연한 결과다.

 

프로그램의 설정값을 입력하는 목적의 Child Form을 만들 경우 사용자 입장에서는 이전에 입력한 값이 그대로 보여지니 이 방법이 내가 설계한 프로그램에는 가장 적합한 해결책인 것이다.

만약 Form을 삭제하고 다시 객체를 생성해서 Child Form을 띄울 경우 기존에 입력했던 값들을 다시 Parent Form에서 받아 오든, 아니면 특정 위치에 저장을 해서 불러오든 해야하기에 구현의 까다로움이 존재하므로 굳이 이 방법을 사용하지 않아도 좋은 프로그램을 만들 수 있다.

Posted by [ 브랜든 ]
,

Trading 시스템을 내가 아닌 제 3자의 사용자적 입장에서 사용하도록 시뮬레이션 해 보았을 때

자식 Form을 새로 띄워서 값을 입력 받거나 확인할 수 있게 하는 작업이 많이 필요하단 것을 알게 되었다. 

(기능적으로 그렇지만 보기에, 사용하기에 신규Form을 보여주는 것이 더 깔끔한...)

 

  • 부모 Form : Form1 (Delegate Test) 

'로그인' 버튼과 결과를 출력해줄 TextBox를 갖는 부모 Form

  • 자식 Form : Form2 (Login)

'아이디'와 '비밀번호'를 입력할 수 있는 TextBox와 로그인 버튼을 갖는 자식 Form

 

테스트 구현 방식은

부모 Form(Form1)에서 아이디 값을 넘겨주어 자식 Form(Form2)에서는 아이디가 자동으로 입력되고

자식 Form에서 비밀번호 입력 후 '로그인' 버튼을 누르면 

자식 Form이 사라짐과 동시에 부모 Form의 TextBox에 입력받은 비밀번호를 출력하도록 한다. 

 

그러면 두 Form 간에 데이터를 주고 받는 테스트가 완료!

 

1. 부모 Form -> 자식 Form

 

여러 다른 방법이 있는지는 모르겠지만, 내가 구현한 방법은 생각보다 간단하다.

 

[ 부모 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public partial class Form1 : Form
    {
        static string static_id = "brandon";          // 자식 Form에 넘겨줄 ID 값
        Form2 Child = new Form2(static_id);           // 자식 Form 생성자

        public Form1()
        {
            InitializeComponent();

        }

        private void 로그인ToolStripMenuItem_Click(object sender, EventArgs e)  // 로그인 버튼을 눌렀을 때
        {
            Child.Owner = this;
            Child.ShowDialog();                     
        }
    }
}

[ 자식 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public partial class Form2 : Form
    {
        string global_id = string.Empty;

        public Form2(string id)           // 자식 Form의 생성자 - 부모 Form으로부터 값을 전달 받음
        {
            InitializeComponent();
            global_id = id;
        }

        private void Form2_Load(object sender, EventArgs e) // Form2가 보여질때 설정
        {
            textBox1.Text = global_id;    // Form2에 부모 Form으로부터 받은 id 값을 미리 설정
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }
    }
}

[ 결과 ]

자식 Form(Login)이 표시됨과 동시에 부모 Form에서 받은 'brandon'이란 ID 값이 자동으로 입력됨.

 

2. 자식 Form -> 부모 Form

 

이 경우에는 delegate라는것을 사용하는데, C++에서의 함수포인터와 비슷한 개념이다.

'대리자'라는 뜻의 이 delegate는 메소드를 대신해서 호출해 주는 역할을 한다고 생각하면 된다. 

 

[ 부모 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public delegate void LoginGetEventHandler(string id, string password); // 자식 Form EventHandler

    public partial class Form1 : Form
    {
        static string static_id = "brandon";
        Form2 Child = new Form2(static_id);

        public Form1()
        {
            InitializeComponent();
            Form2.LoginGetEvent += new LoginGetEventHandler(this.Login_Process); // EventHandler 등록
        }

        private void 로그인ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Child.Owner = this;
            Child.ShowDialog();                     
        }

        private void Login_Process(string id, string password) // Event 발생 시, 처리할 함수 선언
        {
            string test_result = string.Empty;
            test_result = String.Format("ID : {0}, PW : {1}", id, password);
            textBox1.Text = test_result;  // 자식 Form에서 수신한 값 표시
        }
    }
}

[ 자식 Form ]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace delegate_test
{
    public partial class Form2 : Form
    {
        public static LoginGetEventHandler LoginGetEvent;  // 부모 Form에서 등록한 EventHandler 선언

        string global_id = string.Empty;

        public Form2(string id) 
        {
            InitializeComponent();
            global_id = id;
        }

        private void Form2_Load(object sender, EventArgs e) 
        {
            textBox1.Text = global_id;
        }

        private void button1_Click(object sender, EventArgs e) // 로그인 버튼을 눌렀을 때
        {
            this.Close();
            LoginGetEvent(textBox1.Text, textBox2.Text);  // 입력된 ID와 PASSWORD 값을 EventHandler에 전달
        }
    }
}

[ 결과 ]

비밀번호를 'asdf1234!@#$'로 입력 후 로그인 버튼 클릭
자식 Form에서 입력한 값을 부모 Form에서 받아서 출력

 

나도 C#을 처음 해보는 것이기에 더 좋고, 간단하며, 오류 없는 방법이 있을지는 모르겠다. 

Trading 시스템의 '사용자 로그인' 부분을 구현하면서 필요한 기능이었기에 어떻게 활용하였는지는

아래 링크에서 확인해 보자. 

Posted by [ 브랜든 ]
,