====== UBi 프레임워크 업무화면(UX) 템플릿 분석 ======
> **문서 정보**
> * 작성일: 2026-03-21
> * 대상: UBi3 Framework 기반 업무화면 개발자
> * 템플릿: UBi_FORM_SEC
> * 프레임워크 버전: UBi3 / .NET Framework 4.7.2
[[makeUX|- 새로운 프로젝트(화면)을 개발하기 위한 템플릿 생성]]
{{ :ubi_framework_dokuwiki_guide_structure.svg |}}
----
===== 1. 개요 =====
UBi 프레임워크는 유비덤(UBiDum)에서 개발한 WinForm 기반 업무화면 개발 프레임워크입니다. 개발자는 ''UBi_FORM_SEC'' 템플릿 프로젝트를 복사하여 새로운 업무화면을 빠르게 구성할 수 있습니다.
==== 1.1 기술 스택 ====
| **구분** | **기술/버전** |
| 런타임 | .NET Framework 4.7.2 |
| UI 컨트롤 | DevExpress v20.1 |
| 프레임워크 | UBi3 Framework (UBi.WinForm.Controls)|
| 데이터 통신 | REST API (UBi.Net.RestfulClient) |
| DB 프로시저 | Oracle Stored Procedure (PKG 패턴) |
| 프로젝트 형태 | Class Library (DLL) |
==== 1.2 프레임워크 주요 DLL ====
| **DLL 명칭** | **역할** |
| UBi.dll | 코어 유틸리티, 확장 메서드 (Nvl 등) |
| UBi.IO.dll | 파일 입출력 처리 |
| UBi.Net.dll | 네트워크 통신 기반 |
| UBi.Net.RestfulClient.dll | REST API 클라이언트 |
| UBi.Net.Sockets.dll | 소켓 통신 |
| UBi.Platform.dll | 플랫폼 공통 기능 |
| UBi.Platform.Images.dll | 이미지 처리 |
| UBi.WinForm.dll | WinForm 기반 클래스 |
| UBi.WinForm.Controls.dll | UI 컨트롤 (BaseModule, DataManager 등)|
----
===== 2. 프로젝트 구성 =====
==== 2.1 템플릿 폴더 구조 ====
UBi_FORM_SEC/
├── Properties/
│ ├── AssemblyInfo.cs ← 어셈블리 메타정보 (프로젝트명, 설명)
│ ├── licenses.licx ← DevExpress 라이선스
│ ├── Resources.resx ← 리소스 정의
│ └── Resources.Designer.cs ← 리소스 자동 생성 코드
├── UBi_FORM_SEC.cs ← ★ 메인 비즈니스 로직 (개발자 작성 영역)
├── UBi_FORM_SEC.Designer.cs ← ★ 디자이너 코드 (Visual Studio 디자이너)
├── UBi_FORM_SEC.resx ← 폼 리소스
└── UBi_FORM_SEC.csproj ← 프로젝트 파일
==== 2.2 핵심 파일 설명 ====
=== UBi_FORM_SEC.cs (메인 로직) ===
개발자가 직접 코드를 작성하는 파일입니다. ''BaseModule''을 상속받아 업무화면을 구현합니다.
=== UBi_FORM_SEC.Designer.cs (디자이너) ===
Visual Studio 디자이너가 자동 생성하는 파일입니다. 컨트롤 배치, DataAdapter 설정, 컬럼 정의 등이 포함됩니다.
=== UBi_FORM_SEC.csproj (프로젝트 설정) ===
빌드 설정, 참조 DLL, PostBuild 이벤트(afterbuild) 등을 정의합니다.
----
===== 3. 새 업무화면 생성 절차 =====
==== 3.1 Step 1: 템플릿 복사 ====
- ''UBi_FORM_SEC'' 폴더를 복사합니다
- 폴더명을 새 업무화면 ID로 변경합니다 (예: ''UBi_FORM_ORD001'')
- 폴더 내 모든 파일명에서 ''UBi_FORM_SEC''를 새 이름으로 변경합니다
예) UBi_FORM_SEC → UBi_FORM_ORD001
UBi_FORM_SEC.cs → UBi_FORM_ORD001.cs
UBi_FORM_SEC.Designer.cs → UBi_FORM_ORD001.Designer.cs
UBi_FORM_SEC.csproj → UBi_FORM_ORD001.csproj
UBi_FORM_SEC.resx → UBi_FORM_ORD001.resx
==== 3.2 Step 2: 클래스명 변경 ====
''UBi_FORM_SEC.cs''와 ''UBi_FORM_SEC.Designer.cs'' 파일에서 클래스명을 변경합니다.
// 변경 전
public partial class 프로젝트명을지정하시오 : BaseModule
// 변경 후 (예시)
public partial class UBi_FORM_ORD001 : BaseModule
**주의:** ''.cs'' 파일과 ''.Designer.cs'' 파일 모두에서 클래스명을 동일하게 변경해야 합니다.
==== 3.3 Step 3: 문서 주석 작성 ====
클래스 상단의 XML 주석을 작성합니다.
///
/// 주문등록 화면
/// 고객 주문을 등록하고 관리하는 화면입니다.
/// 작성자 : 홍길동
/// 작성일 : 2026-03-21
///
[ToolboxItem(false)]
public partial class UBi_FORM_ORD001 : BaseModule
==== 3.4 Step 4: AssemblyInfo.cs 수정 ====
''Properties/AssemblyInfo.cs''에서 어셈블리 정보를 수정합니다.
[assembly: AssemblyTitle("UBi_FORM_ORD001")]
[assembly: AssemblyDescription("주문등록 화면")]
==== 3.5 Step 5: 솔루션에 프로젝트 추가 ====
- Visual Studio에서 솔루션 열기
- 솔루션 탐색기 → 우클릭 → 기존 프로젝트 추가
- 새로 만든 ''.csproj'' 파일 선택
----
===== 4. 아키텍처 및 핵심 컴포넌트 =====
==== 4.1 클래스 상속 구조 ====
System.Windows.Forms.UserControl
└─ BaseModule (UBi.WinForm.Controls)
└─ 업무화면 클래스 (개발자 작성)
''BaseModule''은 MDI 자식 폼으로 동작하며, 공통 버튼 인터페이스(IButton)를 제공합니다.
==== 4.2 UBiDataManager (데이터 매니저) ====
화면의 데이터 접근을 총괄하는 컴포넌트입니다.
| **속성** | **설명** | **예시값** |
| ServiceUrl | REST API 서버 주소 | http://localhost:5000/api|
| ServiceName | DB 서비스 구분 이름 | SEC_DEV |
| ServiceUserId | 서비스 접속 사용자 ID | a(기본) |
| ServicePassword | 서비스 접속 비밀번호 | a(기본) |
| IsFullLoad | 전체 로드 여부 | false |
| AdapterList | 하위 DataAdapter 목록 | - |
**초기화 방법:**
// Form_Load에서 호출
uBiDataManager1.Init();
// → IsOnLoadSelect="Y"인 DataAdapter가 자동으로 SELECT 프로시저 실행
==== 4.3 UBiDataAdapter (데이터 어댑터) ====
개별 데이터 세트(DataSet)에 대한 CRUD 작업을 담당합니다.
| **속성** | **설명** |
| NAME | 어댑터 식별자 (예: "TEST") |
| DESCRIPTION | 어댑터 설명 |
| IsRoot | 루트 어댑터 여부 |
| IsOnLoadSelect | 화면 로드 시 자동 조회 여부 ("Y"/"N") |
| MODE | 데이터 모드 (STATIC 등) |
| SELECT_PROCEDURE_ID | 조회 프로시저 이름 (예: PKG_SYS$GET_CHILDS) |
| INSERT_PROCEDURE_ID | 입력 프로시저 이름 |
| UPDATE_PROCEDURE_ID | 수정 프로시저 이름 |
| DELETE_PROCEDURE_ID | 삭제 프로시저 이름 |
| LookupLayOut | 컬럼 속성 정의 목록 (UBiColProperty) |
| SelectParam | 조회 파라미터 목록 (UBiParam) |
=== 프로시저 호출 규칙 ===
Oracle 저장 프로시저는 패키지 형태로 관리됩니다.
명명규칙: PKG_{업무구분}${프로시저명}
예시: PKG_SYS$GET_CHILDS
=== 파라미터(UBiParam) 구조 ===
| **속성** | **설명** | **예시** |
| ARGUMENT_NAME | 프로시저 파라미터 이름 | A_PARENT_PATH |
| DATA_TYPE | 데이터 타입 | VARCHAR / INT |
| DATA_LENGTH | 데이터 길이 | 200 |
| IN_OUT | 입출력 방향 | IN / OUT |
| IS_FIND | 조건 검색 사용 여부 | true |
| SORT_ORDER | 파라미터 순서 | 1, 2, 3... |
| SOURCE_NAME | 소스 바인딩 이름 | A_PARENT_PATH |
**표준 OUT 파라미터:**
모든 프로시저는 다음 OUT 파라미터를 포함합니다:
* ''N_RETURN'' (INT) — 결과 코드 (0: 성공)
* ''V_RETURN'' (VARCHAR, 4000) — 결과 메시지
==== 4.4 UBiColProperty (컬럼 속성) ====
그리드 및 Lookup 컬럼의 속성을 정의합니다.
| **속성** | **설명** | **예시** |
| FIELD_NAME | DB 컬럼명 | DATA_ID |
| TITLE | 화면 표시 제목 | 데이터번호 |
| TITLE_ID | 다국어 제목 ID | DATA_ID |
| DATA_TYPE | 데이터 타입 | System.Int64, System.String, System.Decimal |
| COL_TYPE | 컬럼 표시 유형 | NUMERIC (기본은 TEXT) |
| DATA_ALIGN | 정렬 방식 | Near(좌), Far(우) |
| SIZE | 컬럼 너비 | 80 |
| ORDER | 표시 순서 (10단위 증가) | 10, 20, 30... |
| BACK_COLOR | 배경색 | System.Drawing.Color.White|
| FORE_COLOR | 글자색 | System.Drawing.Color.Black|
==== 4.5 UBiLayoutControl (레이아웃 컨트롤) ====
DevExpress의 LayoutControl을 확장한 컨트롤로, 화면의 전체 레이아웃을 관리합니다. ''Dock = Fill'' 모드로 폼 전체를 차지하며, 내부에 조회조건 영역과 데이터 그리드 등을 배치합니다.
----
===== 5. 버튼 인터페이스 (IButton) =====
''BaseModule''은 MDI 프레임(''UBiMdiForm'')의 공통 툴바 버튼과 연결되는 가상 메서드를 제공합니다. 개발자는 필요한 메서드만 ''override''하여 구현합니다.
==== 5.1 버튼 메서드 일람 ====
| **메서드** | **기능** | **설명** |
| ''OnInitClick'' | 초기화 | 조회조건 초기화 등 화면 리셋 |
| ''OnSearchClick'' | 조회 | DataAdapter.Select() 호출 |
| ''OnAddClick'' | 추가 | 그리드 행 추가 등 |
| ''OnDeleteClick'' | 삭제 | 그리드 행 삭제 등 |
| ''OnSaveClick'' | 저장 | DataAdapter.Update() 호출 |
| ''OnHelpClick'' | 도움말 | PDF 매뉴얼 표시 |
| ''OnCloseClick'' | 닫기 | 화면 종료 시 정리 작업 |
==== 5.2 조회 버튼 구현 예시 ====
public override void OnSearchClick(UBiMdiForm f)
{
base.OnSearchClick(f);
try
{
UBiMessageBox.ShowWait("Loading...", "Loading...");
// 방법 1: 컨트롤에서 직접 호출
gridMain.DataAdapter.Select(true);
// 방법 2: DataManager에서 이름으로 호출
// uBiDataManager1.GetAdapter("TEST").Select(true);
}
catch (Exception ex)
{
ex.UBiShowException(this);
}
finally
{
UBiMessageBox.CloseWait();
}
}
==== 5.3 저장 버튼 구현 예시 ====
public override void OnSaveClick(UBiMdiForm f)
{
base.OnSaveClick(f);
try
{
UBiMessageBox.ShowWait("Wait", "Saving into Database...");
// 저장 전 유효성 검사
// ...
ResponseDB res = gridMain.DataAdapter.Update();
if (res.Code == 0)
{
UBiMessageBox.Show(res.Message, MessageBoxIcon.Information, true);
OnSearchClick(f); // 재조회
}
else
{
UBiMessageBox.Show(res.Message, MessageBoxIcon.Error, true);
}
}
catch (Exception ex)
{
ex.UBiShowException(this);
}
finally
{
UBiMessageBox.CloseWait();
}
}
----
===== 6. 그리드 이벤트 처리 =====
UBi 프레임워크의 그리드(''UBiGridView'')는 DevExpress GridView를 확장한 컨트롤입니다. 다양한 이벤트를 통해 셀 편집, 스타일링, 합계 계산 등을 처리할 수 있습니다.
==== 6.1 셀 값 변경 이벤트 (CellValueChanged) ====
특정 컬럼의 값이 변경되었을 때 처리합니다.
gridMain.CellValueChanged += (a, b) =>
{
if (b.Column.FieldName.Equals("IS_CHK"))
{
// 체크박스 변경 시 처리 코드
}
};
==== 6.2 조건부 행 스타일 (RowCellStyle) ====
데이터 값에 따라 셀의 글자색, 배경색 등을 동적으로 변경합니다.
gridMain.RowCellStyle += (a, b) =>
{
if (b.RowHandle >= 0)
{
UBiGridView view = a as UBiGridView;
// 수량이 0보다 크면 파란색
if (view.GetRowCellValue(b.RowHandle, "PLAN_QTY").Nvl("0").ToInt() > 0)
{
b.Appearance.ForeColor = Color.Blue;
}
// 특정 컬럼 값에 따라 빨간색
if (b.Column.FieldName.Equals("ISBUY"))
{
if (b.CellValue.Nvl("N").Equals("Y"))
b.Appearance.ForeColor = Color.Red;
}
}
};
==== 6.3 셀 편집 제한 (ShowingEditor) ====
특정 조건에서 셀 편집을 막아야 할 때 사용합니다.
gridMain.ShowingEditor += (a, b) =>
{
if (gridMain.GetFocusedDataRow()["INPUT_LOCK"].Nvl("Y").Equals("Y"))
{
b.Cancel = true;
UBiMessageBox.Show("투입 LOCK이 걸려 있습니다.",
MessageBoxIcon.Information, false);
SystemSounds.Beep.Play();
return;
}
};
==== 6.4 조건부 커스텀 합계 (CustomSummaryCalculate) ====
특정 조건을 만족하는 행만 합계에 포함시킬 때 사용합니다.
decimal sumAMT = 0;
gridMain.CustomSummaryCalculate += (a, b) =>
{
gridSub.UpdateCurrentRow();
if (!b.IsTotalSummary
|| !((b.Item as GridSummaryItem).FieldName == "AMT"))
return;
if (b.SummaryProcess == DevExpress.Data.CustomSummaryProcess.Start)
{
sumAMT = 0;
}
if (b.SummaryProcess == DevExpress.Data.CustomSummaryProcess.Calculate)
{
if (b.Row is DataRowView r)
{
if (r.Row["END_CHK"].Nvl().Equals("Y"))
{
if ((b.Item as GridSummaryItem).FieldName == "AMT")
sumAMT += (decimal)b.FieldValue;
}
}
}
if (b.SummaryProcess == DevExpress.Data.CustomSummaryProcess.Finalize)
{
if ((b.Item as GridSummaryItem).FieldName == "AMT")
b.TotalValue = sumAMT;
}
};
==== 6.5 기타 유용한 그리드 메서드 ====
| **메서드/속성** | **기능** |
| ''gridMain.ClearColumnsFilter()'' | 그리드 필터 조건 초기화 |
| ''gridMain.GetFocusedDataRow()'' | 현재 포커스 행의 DataRow 반환 |
| ''gridMain.UpdateCurrentRow()'' | 현재 행 데이터 갱신 |
----
===== 7. 화면 간 파라미터 전달 =====
화면이 호출될 때 부모 화면에서 전달하는 파라미터를 ''Param'' 속성으로 접근합니다.
private void Form_Load(object sender, EventArgs e)
{
if (Param != null)
{
// 파라미터 접근
string message = Param["message"].Nvl();
UBiMessageBox.Show(message, MessageBoxIcon.Information, true);
}
uBiDataManager1.Init();
}
==== 파라미터 전달 패턴 ====
| **메서드** | **설명** |
| ''Param["키"]'' | 문자열 값 가져오기 |
| ''.Nvl()'' | null 안전 변환 (빈 문자열) |
| ''.Nvl("기본값")'' | null일 때 기본값 반환 |
| ''.ToInt()'' | 정수 변환 |
----
===== 8. 공통 유틸리티 =====
==== 8.1 UBiMessageBox ====
| **메서드** | **설명** |
| ''UBiMessageBox.Show(msg, icon, modal)'' | 일반 메시지 표시 |
| ''UBiMessageBox.ShowWait(title, msg)'' | 대기(로딩) 메시지 표시 |
| ''UBiMessageBox.CloseWait()'' | 대기 메시지 닫기 |
==== 8.2 확장 메서드 ====
| **메서드** | **설명** |
| ''.Nvl()'' | null → 빈 문자열 변환 |
| ''.Nvl("default")'' | null → 기본값 변환 |
| ''.ToInt()'' | 문자열 → int 변환 |
| ''ex.UBiShowException(this)'' | Exception을 화면에 표시 |
==== 8.3 ResponseDB (데이터 응답 객체) ====
| **속성** | **설명** |
| Code | 결과 코드 (0: 성공, 그 외: 실패) |
| Message | 결과 메시지 |
----
===== 9. 디자이너 설정 가이드 =====
==== 9.1 UBiDataAdapter 디자이너 속성 설정 ====
Visual Studio 디자이너에서 ''uBiDataManager1''을 선택한 후 속성 창에서 설정합니다.
- **ServiceUrl** → REST API 서버 주소 설정
- **ServiceName** → DB 서비스명 설정 (환경에 맞게 변경)
- **AdapterList** → 어댑터 추가/편집
각 DataAdapter에서 설정할 항목:
- **NAME** → 어댑터 식별 이름
- **SELECT_PROCEDURE_ID** → 조회 프로시저
- **INSERT_PROCEDURE_ID** → 등록 프로시저
- **UPDATE_PROCEDURE_ID** → 수정 프로시저
- **DELETE_PROCEDURE_ID** → 삭제 프로시저
- **IsOnLoadSelect** → "Y"이면 화면 로드 시 자동 조회
- **LookupLayOut** → 컬럼 정의 (UBiColProperty 컬렉션)
- **SelectParam** → 조회 파라미터 (UBiParam 컬렉션)
==== 9.2 컬럼 추가 절차 ====
- DataAdapter의 **LookupLayOut** 컬렉션 편집기를 엽니다
- Add 버튼으로 ''UBiColProperty''를 추가합니다
- 각 속성을 설정합니다:
FIELD_NAME : DB 컬럼명 (예: ORDER_NO)
TITLE : 화면 표시명 (예: 주문번호)
TITLE_ID : 다국어 ID (예: ORDER_NO)
DATA_TYPE : System.String | System.Int64 | System.Decimal
COL_TYPE : (기본 TEXT) 또는 NUMERIC
DATA_ALIGN : Near(좌측) | Center(중앙) | Far(우측)
SIZE : 컬럼 너비 (기본 80)
ORDER : 표시 순서 (10, 20, 30...)
==== 9.3 파라미터 추가 절차 ====
- DataAdapter의 **SelectParam** 컬렉션 편집기를 엽니다
- Add 버튼으로 ''UBiParam''을 추가합니다
ARGUMENT_NAME : 프로시저 파라미터명 (예: A_ORDER_DATE)
DATA_TYPE : VARCHAR | INT
DATA_LENGTH : 문자열 길이 (예: 200)
IN_OUT : IN 또는 OUT
SORT_ORDER : 파라미터 순서 (1, 2, 3...)
SOURCE_NAME : 바인딩 소스 이름
----
===== 10. 빌드 및 배포 =====
==== 10.1 빌드 구성 ====
프로젝트는 Class Library(DLL) 형태로 빌드됩니다.
| **구성** | **출력 경로** | **최적화** |
| Debug | bin\Debug\ | 비활성화 |
| Release | bin\Release\ | 활성화 |
==== 10.2 PostBuild 이벤트 ====
빌드 완료 후 자동으로 ''afterbuild'' 스크립트가 실행됩니다.
$(SolutionDir)\afterbuild $(SolutionDir) $(ProjectDir) $(TargetFileName)
이 스크립트는 빌드된 DLL을 실행 환경의 dll 폴더로 복사합니다.
==== 10.3 프로젝트 참조 ====
새 프로젝트 생성 시 다음 참조가 필요합니다:
* **POPUP_COMMON** — 공통 팝업 프로젝트
* **UXHelper** — UX 도우미 유틸리티
* **UBi 프레임워크 DLL** — ''UBi3FrameWork/FrameWorkReference/'' 경로의 DLL 파일들
* **DevExpress v20.1** — UI 컨트롤 라이브러리
----
===== 11. 코딩 컨벤션 =====
==== 11.1 네임스페이스 ====
모든 업무화면은 ''UX'' 네임스페이스를 사용합니다.
namespace UX
{
public partial class UBi_FORM_ORD001 : BaseModule
{ }
}
==== 11.2 코드 작성 규칙 ====
* **try-catch-finally 패턴** 필수: 조회/저장 등 DB 작업 시 항상 사용
* **UBiMessageBox.ShowWait / CloseWait** 쌍: 장시간 작업 시 반드시 쌍으로 사용
* **base 호출**: ''override'' 메서드에서 반드시 ''base.메서드명(f)'' 먼저 호출
* **이벤트 등록**: ''Form_Load''에서 그리드 이벤트를 람다로 등록
* **주석**: 한글 주석으로 비즈니스 로직 설명 기재
==== 11.3 명명 규칙 ====
| **대상** | **규칙** | **예시** |
| 프로젝트명 | UBi_FORM_{업무코드} | UBi_FORM_ORD001 |
| 클래스명 | 프로젝트명과 동일 | UBi_FORM_ORD001 |
| DataAdapter NAME | 대문자 영어 | TEST, ORDER, ITEM |
| 프로시저 ID | PKG_{업무}${동작} | PKG_ORD$GET_LIST |
| 컬럼 FIELD_NAME | 대문자 스네이크 | ORDER_NO, CUST_NAME |
----
===== 12. 자주 묻는 질문 (FAQ) =====
=== Q1. 화면 로드 시 자동 조회가 안 됩니다 ===
→ DataAdapter의 **IsOnLoadSelect** 속성이 "Y"로 설정되어 있는지 확인하세요. 또한 ''Form_Load''에서 ''uBiDataManager1.Init()''이 호출되고 있는지 확인하세요.
=== Q2. 저장 후 ResponseDB.Code가 0이 아닙니다 ===
→ DB 프로시저의 ''N_RETURN'' OUT 파라미터 값을 확인하세요. 프로시저 내부에서 오류 발생 시 0이 아닌 값을 반환합니다. ''V_RETURN''에 상세 오류 메시지가 포함됩니다.
=== Q3. 그리드 컬럼이 표시되지 않습니다 ===
→ DataAdapter의 **LookupLayOut** 컬렉션에 컬럼 정의가 추가되어 있는지 확인하세요. ORDER 값이 올바르게 설정되어야 합니다.
=== Q4. 빌드 후 화면이 반영되지 않습니다 ===
→ PostBuild 이벤트(afterbuild)가 정상 실행되었는지 확인하세요. 실행 환경의 dll 폴더에 최신 DLL이 복사되었는지 점검합니다.
=== Q5. REST API 연결이 실패합니다 ===
→ ''uBiDataManager1''의 **ServiceUrl**, **ServiceName**, **ServiceUserId**, **ServicePassword** 속성이 올바른지 확인하세요. 개발 환경에 맞게 설정을 변경해야 합니다.
----
===== 13. 참고 링크 =====
* DevExpress v20.1 문서: [[https://docs.devexpress.com/WindowsForms/|DevExpress WinForms Documentation]]
* .NET Framework 4.7.2: [[https://docs.microsoft.com/dotnet/framework/|Microsoft .NET Framework]]
----
//이 문서는 UBi_FORM_SEC 템플릿 프로젝트를 기반으로 작성되었습니다.//\\
//최종 수정: 2026-03-21//