본문 바로가기

IT 살이/04. 기술 - 프로그래밍

개발 프레임워크 만들기 대장정 41 - 화면 객체 로딩 테스트

지난 포스트까지는 메뉴 정보를 로딩해서 트리로 출력하는 과정을 봤다. 오늘은 트리의 최종 노드를 클릭했을 때 화면을 로딩시켜보자.

샘플 화면을 하나 추가하자.

항목 추가 템플릿에서 User Control(WPF) 템플릿을 선택하고 이름을 UserMgmt.xaml이라고 넣는다.

이렇게 해서 추가된 사용자 컨트롤 코드를 좀 수정해야 한다.

우선 베이스 클래스를 우리가 이전에 만든 BongControlBase로 수정한다.

public partial class UserMgmt : BongControlBase

그런 다음 xaml 마크업 코드도 다음처럼 수정한다.

<Bong:BongControlBase x:Class="BONG.WIN.CO.UserMgmt.UserMgmt"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:Bong="clr-namespace:Bong.Win;assembly=Bong.Win"

    Height="Auto" Width="Auto">

    <Border BorderBrush="Black" BorderThickness="2">

        <DockPanel Name="dockPanel1" LastChildFill="True" >

            <Button Height="23" Name="btnHello" Width="75" Click="btnHello_Click">Hello</Button>

        </DockPanel>

    </Border>

</Bong:BongControlBase>

이게 무슨 말인가하면…모르겠다면, 이전 포스트를 보자.

간단히 말하면 UserControl의 베이스 클래스를 사용자 정의 클래스( 여기서는 BongControlBase)로  지정하다보니 이런 모양이 되었다는 것이다.

( 물론 실전 프로젝트에서 개발자들에게 이렇게 수작업을 시킬 수는 없는 일일 것이다. Visual Studio 메뉴에 File->Export Templates… 가 있다. 이것을 사용하면 미리 수정된 사용자 컨트롤을 추가할 수 있는 템플릿이 앞의 그림의 항목 추가 템플릿 창에 나오게 할 수 있다. 이 방법에 대해서는 구글링해보면 나올 것으로 본다. Export Templates, Visual Studio를 적절히 조합해서 검색해 보자.)

달봉이는 이 사용자 컨트롤에 버튼을 하나 올렸놨다.

이 사용자 컨트롤을 메뉴 정보에 등록하는 과정은 이전 포스트에서 한 대로이다. 그러나 그 정보가 잘못 등록되어서 다시 다음처럼 수정했다.

dr = dt.NewRow();

dr[MenuHelper.MenuIDColumnName] = "010101";

dr[MenuHelper.MenuNameColumnName] = "01 화면";

dr[MenuHelper.MenuTypeColumnName] = MenuHelper.FileMenuTypeCode;

dr[MenuHelper.FullyQualifiedTypeNameColumnName] = "BONG.WIN.CO.UserMgmt.UserMgmt";

dr[MenuHelper.FileNameColumnName] = "BONG.WIN.CO.UserMgmt";

dr[MenuHelper.LoadUrlColumnName] = loadUrl;

dr[MenuHelper.ParentMenuIDColumnName] = "0101";

dt.Rows.Add(dr);

하단의 링크를 통해서 수정된 소스를 받을 수 있다.

이제 트리를 클릭했을때 화면을 탭으로 출력하는 코드를 보자. 우선 트리 최종 노드를 클릭했을때 반응할 수 있는 이벤트 핸들러를 등록하는 코드를 보자.

private void ProcessItem(TreeViewItem parentItem, IMenuItemInfo parentItemInfo)

{

    TreeViewItem treeItem = null;

    List<IMenuItemInfo> lstMenuItemInfos = parentItemInfo.GetChildren();

    if (lstMenuItemInfos == null)

        return;

    foreach (IMenuItemInfo itemInfo in lstMenuItemInfos)

    {

        treeItem = new TreeViewItem();

        treeItem.Header = itemInfo.Name;

        treeItem.Tag = itemInfo;

        FileMenuItemInfo item = itemInfo as FileMenuItemInfo ;

        if( item != null )

        {

            treeItem.MouseUp += new MouseButtonEventHandler(treeItem_MouseUp);

        }

        parentItem.Items.Add(treeItem);

 

        ProcessItem(treeItem, itemInfo);

    }

}

메뉴 트리를 구성할 때, 메뉴가 최종 노드( FileMenuItemInfo)인 경우만 트리 노드의 MouseUp이벤트에 핸들러 treeItem_MouseUp를 등록하고 있다. 그리고 이전에 트리 노드treeItem의 Tag 속성에 메뉴 정보 객체 itemInfo를 저장해 두고 있다. 나중에 트리 노드가 클릭되면 Tag 속성에 저장해뒀던 메뉴 정보 객체를 복원해서 로딩할 화면에 대한 정보를 얻게 될 것이다.

treeItem_MouseUp의 구현 내용은 다음과 같다.

void treeItem_MouseUp(object sender, MouseButtonEventArgs e)

{

    TreeViewItem item = sender as TreeViewItem;

    //Tag 속성에 메뉴 정보 객체 복원

    FileMenuItemInfo menuInfo = item.Tag as FileMenuItemInfo;

    if (menuInfo != null)

    {

        string elemetName = menuInfo.ElementInfo.FullyQualifiedTypeName;

        FileMenuItemInfo existigItemInfo = null;

        //이미 같은 화면이 로딩되어 있는지 확인

        //이미 로딩되어 있다면 탭을 생성하지 않고 리턴

        foreach (TabItem existingItem in tabControl1.Items)

        {

            existigItemInfo = existingItem.Tag as FileMenuItemInfo;

            if (existigItemInfo != null &&

                existigItemInfo.ElementInfo.FullyQualifiedTypeName == elemetName)

            {

                existingItem.IsSelected = true;

                return;

            }

        }

        // Spring.NET 객체 생성기를 통해서 화면 객체를 얻는다.

        Dalbong2ControlBase  uiElement =

        ( Dalbong2ControlBaseDalbong2WinAppContext.XmlObjectFactory.GetObject(elemetName);

        //탭 컨트롤에 추가할 탭을 준비한다.

        TabItem tabItem = new TabItem();

        tabItem.Header = menuInfo.Name;

        tabItem.Tag = menuInfo;

        ScrollViewer sv = new ScrollViewer();

        sv.Content = uiElement;

        Frame f = new Frame();

        f.MinHeight = 300;

        f.MinWidth=300;

        f.BorderBrush = Brushes.Blue;

        f.BorderThickness = new Thickness(2);

        f.Content = sv;

 

        tabItem.Content = f;

        //탭을 탭 컨트롤에 추가한다.

        this.tabControl1.Items.Add(tabItem);

        tabItem.IsSelected = true;

    }

}

이게 끝이다. 트리 노드의 Tag 속성에서 메뉴 정보 객체를 복원한다.

그 다음 탭 컨트롤의 탭들중에 이미 해당 화면 객체가 로딩되어 있는지를 확인한다. 이미 로딩되었는지 확인하는 로직에서 탭의 Tag 속성에 저장된 FileMenuItemInfo 객체를 이용하고 있다. 이미 로딩되어 있다면 해당 탭을 선택해주고 리턴한다.

아직 로딩되어 있지 않다면 Spring.NET 컨테이너로부터 객체를 해당 화면 객체를 얻는다( 이 부분의 코드도 약간 수정되었다. 뭔지는 기억이 안난다 –_-;;)

 

그 다음 탭을 하나 동적으로 생성한다. 코드에서는 탭에 바로 화면 객체를 할당하지 않고 Frame 객체를 하나 생성해서 그곳에 화면을 넣고 그 Frame 객체를 탭의 컨텐트로 지정하고 있다.

탭을 탭 컨트롤에 추가하고 선택해주면 된다.

다음은 실행시킨 모습이다.

다운로드 받은 코드에는 달봉이가 테스트해보느라 이것 저것 들어 있을 것이다. 최종 코드가 될때까지 참고 테스트해보길 바란다.
UserMgmt 화면에서 Hello 버튼을 클릭하면 WCF 서비스를 호출하는 부분이 있다. 이 부분은 우선 주석처리하고 실행시키길 바란다.