프로그래밍 기술/WPF

[WPF] 4. 탐색 - 4.3 탐색 종합 세트, 마법사

언제나휴일 2016. 5. 24. 15:29
반응형

4. 탐색 - 4.3 탐색 종합 세트, 마법사



4.3 탐색 종합 세트, 마법사

 

 WPF에서는 하나의 작업군을 여러 단계를 거치면서 수행을 하면서 각 단계별로 작업한 내용을 유지하기 위한 마법사를 만들수 있는 방법을 제공하고 있습니다이를 위해 WPF에서는 NavigationWindow를 제공하고 있는데 NavigationService PageFunction을 같이 이용하면 마법사를 만들 수 있습니다.

 

 여기에서는 단계별로 회원의 이름과 나이주소를 입력받는 마법사를 만드는 과정을 통해 이에 대해 설명하려고 합니다.

 

마법사 실행 화면

[그림 4.14] 마법사 실행 화면

   

 먼저, [WPF 응용 프로그램프로젝트를 하나 만드세요.

[그림 4.15]탐색 종합 세트 - 마법사

 

 그리고회원 정보에 대한 클래스를 간단히 만들어서 사용하기로 합시다.

 

Member.cs

namespace 탐색_종합_세트___마법사

{

    public class Member

    {

        public string Name

        {

            get;

            set;

        }

        public string Age

        {

            get;

            set;

        }

        public string Addr

        {

            get;

            set;

        }

        public Member()

        {

            Name = string.Empty;

            Age = string.Empty;

            Addr = string.Empty;

        }

    }

}

 

 마법사를 만들기 위해서는 NavigationWindow에서 파생된 마법사 Window가 필요한데 MemberWizard라고 하겠습니다통합 개발 환경에서 창을 추가하신 후에 다음과 같이 xaml 파일에 태그들을 변경해 주세요. 

MemberWizard

<NavigationWindow x:Class="탐색_종합_세트___마법사.MemberWizard"

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

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

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:탐색_종합_세트___마법사"

        mc:Ignorable="d"

        Title="MemberWizard" Height="300" Width="300"/>

 

 물론, MemberWizard.xaml.cs 파일에서도 기반 클래스 형식을 NavigationWindow로 변경하세요.

 

public partial class MemberWizard : NavigationWindow

{

   ...

}    

 

 MemberWizard 개체는 마법사의 시작 PageFunction 개체를 생성하여 탐색합니다. 시작 PageFuntion 개체에서는 단계 1에 해당하는 PageFunction 개체를 생성하여 탐색하고 각 단계에서는 다음 단계에 해당하는 PageFunction 개체를 생성하여 탐색하는 작업을 수행합니다그리고 특정 단계에서 마침이나 취소를 누르면 그에 따라 MemberWizard 개체는 마법사에서 작업 결과를 DialogResult 속성에 대입하는 것으로 모든 작업을 완료합니다.

 

 MemberPageFun 이름으로 PageFunction을 추가하세요. MemberPageFun은 시작 PageFunction입니다여기에서는 마법사의 작업이 끝났을 때에 사용자가 입력한 회원 정보와 작업을 마친 것인지 취소된 것인지 여부를 알 수 있어야 합니다이를 위해 MemberPageFun에서는 작업 종료 이벤트 멤버를 노출시킵니다그리고 MemberWizard에서는 해당 이벤트에 대한 처리를 위한 핸들러를 추가합니다이와 같은 작업을 위해, 이벤트로 사용할 대리자를 정의해야 합니다그리고 이벤트 처리에 필요한 데이터인 작업이 정상적으로 마쳤는지 취소한 것인지 여부와 사용자가 입력한 회원 정보를 포함하는 이벤트 인자 형식을 정의합시다.

 

MemberReturnEventArgs.cs

using System;

 

namespace 탐색_종합_세트___마법사

{

    public delegate void MemberReturnEventHandler(object sender, MemberReturnEventArgs e);

    public class MemberReturnEventArgs:EventArgs

    {

        bool reuslt;

        Member member;

        public bool Result

        {

            get { return reuslt; }

        }

        public Member MemberData

        {

            get { return member; }

        }

        public MemberReturnEventArgs(bool reuslt, Member member)

        {

            this.reuslt = reuslt;

            this.member = member;

        }

    }

}

 

 그리고, MemberPageFun에 정의한 delegate 형식의 event를 추가하세요그리고, MemberPageFun의 제네릭 형식 인자는 작업을 취소한 것인지 마침을 한 것인지를 확인하기 위해 bool 형식으로 할게요.

 

class MemberPageFun:PageFunction<bool>

{

    ...

    public event MemberReturnEventHandler MemberReturn;

    ...

};

 

MemberPageFun.xaml

<PageFunction

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

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

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

    x:Class="탐색_종합_세트___마법사.MemberPageFun"

    x:TypeArguments="sys:Boolean"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:local="clr-namespace:탐색_종합_세트___마법사"

    mc:Ignorable="d"

    d:DesignHeight="300" d:DesignWidth="300"

    Title="MemberPageFun">

    <Grid>

 

    </Grid>

</PageFunction>

    

 MemberWizard 개체 생성자에서는  MemeberPageFun 개체를 생성한 후에 MemberReturn 이벤트 핸들러를 추가해야겠지요그리고 해당 개체로 탐색합니다.

 

MemberPageFun mpfun = new MemberPageFun();

mpfun.MemberReturn += new MemberReturnEventHandler(mpfun_MemberReturn);

Navigate(mpfun);

 

 이벤트 핸들러에서는 이벤트 인자로 전달된 회원 정보를 보관해 두어야 할 것입니다또한작업이 취소된 것인지 마친 것인지를 DiaglogReult 속성에 대입함으로써 마법사를 사용하는 곳에서 이들 정보를 사용할 수 있게 합니다.

 

member = e.MemberData;

if (DialogResult == null)

{

    DialogResult = e.Result;

}

 

MemberWizard.xaml.cs

using System.Windows.Navigation;

 

namespace 탐색_종합_세트___마법사

{

    /// <summary>

    /// MemberWizard.xaml에 대한 상호 작용 논리

    /// </summary>

    public partial class MemberWizard : NavigationWindow

    {

        Member member;

        public Member MemberData

        {

            get

            {

                return member;

            }

        }

        public MemberWizard()

        {

            InitializeComponent();

            MemberPageFun mpfun = new MemberPageFun();

            mpfun.MemberReturn += new MemberReturnEventHandler(mpfun_MemberReturn);

            Navigate(mpfun);

        }

        void mpfun_MemberReturn(object sender, MemberReturnEventArgs e)

        {

            member = e.MemberData;

            if (DialogResult == null)

            {

                DialogResult = e.Result;

            }

        }

    }

}

  

 MemberPageFun 개체는 마법사의 각 단계에서 수행한 결과를 보관하기 위한 멤버가 필요합니다이에 회원 개체를 생성하여 멤버 필드로 유지할게요.

 

Member member = new Member();

 

 MemberPageFun 개체가 가동이 되면 1단계에 해당하는 이름을 입력받는 PageFunction 개체를 생성하여 탐색하는 작업을 수행해야 합니다이를 위해 PageFuntion에 가상 메서드로 Start를 재정의 합시다통합 개발 환경에서 override를 먼저 치면 재 정의 가능한 항목 창에서 Start 메서드를 선택하세요.

 

protected override void Start()

{

   base.Start();

}

 

 Start 메서드에서는 탐색 기록을 유지하기 위해 KeepAlive 속성을 true로 지정을 할게요.

 

KeepAlive = true;

 

 그리고 1단계에 해당하는 NamePageFun 개체를 생성하고 Return 이벤트 핸들러를 추가한 후에 해당 개체로 탐색합니다.

 

NamePageFun npf = new NamePageFun(member);

npf.Return += new ReturnEventHandler<bool>(npf_Return);

NavigationService.Navigate(npf);

 

 이벤트 핸들러에서는 멤버 이벤트인 MemberReturn이 설정되어 있다면 이를 호출하여 수행한 회원 정보와 작업 취소마침 여부를 전달 합니다.

 

if (MemberReturn != null)

{

    MemberReturn(this,new MemberReturnEventArgs(e.Result,member));

}

  

MemberPageFun.cs

using System.Windows.Navigation;

namespace Ex_마법사

{

    class MemberPageFun:PageFunction<bool>

    {

        Member member = new Member();

        public event MemberReturnEventHandler MemberReturn;

        protected override void Start()

        {

            base.Start();

            KeepAlive = true;

            NamePageFun npf = new NamePageFun(member);

            npf.Return += new ReturnEventHandler<bool>(npf_Return);

            NavigationService.Navigate(npf);

        }

        void npf_Return(object sender, ReturnEventArgs<bool> e)

        {

            if (MemberReturn != null)

            {

                MemberReturn(this,new MemberReturnEventArgs(e.Result,member));

            }

            OnReturn(null);

        }

    }

}

  

 NamePageFun.xaml 파일에서는 이름을 입력받을 수 있고 다음 단계로 탐색하거나 작업을 마치거나 취소할 수 있게 화면 구성부터 할께요다음 장에서 레이 아웃에 대해 다룰 것이니 여기서는 의미를 두지 않을께요다만제네릭 형식 인자를 Boolean으로 바꾸었습니다이는 호출한 곳에서는 작업을 마쳤는지 취소했는지를 알아야 하기 때문입니다참고로, C#에서 bool 형식은 .NET Boolean 형식과 같습니다.

 

NamePageFun.xaml

<PageFunction

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

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

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

    x:Class="탐색_종합_세트___마법사.NamePageFun"

    x:TypeArguments="sys:Boolean"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:local="clr-namespace:탐색_종합_세트___마법사"

    mc:Ignorable="d"

    d:DesignHeight="300" d:DesignWidth="300"

    KeepAlive="True" Title="단계1 - 이름 입력">

    <StackPanel>

        <TextBlock Name="tb_name" Text="이름:"/>

        <TextBox Name="tbox_name" Background="Cyan"/>

        <Button Name="btn_next" Content="다음 단계로" Click="btn_next_Click"/>

        <Button Name="btn_end" Content="마침" Click="btn_end_Click"/>

        <Button Name="btn_cancel" Content="취소" Click="btn_cancel_Click"/>

    </StackPanel>

 

</PageFunction>

 

 NamePageFun 개체가 생성되면서 회원 개체를 입력 인자로 전달받게 하였습니다이는 마법사의 시작 PageFunction MemberPageFun 개체에서 생성한 회원 개체를 멤버 필드로 참조함으로써 사용자가 입력한 이름을 설정하기 위함입니다.

 

public NamePageFun(Member member)

{

    InitializeComponent();

    this.member = member;

}

 

 다음 단계로 버튼을 눌렀을 때에는 사용자가 입력한 이름을 회원 개체의 이름으로 설정하세요그리고 다음 단계인 AgePageFun 개체를 생성하고 Return 이벤트 핸들러를 추가한 후에 탐색합니다.

 

member.Name = tbox_name.Text;

AgePageFun apfun = new AgePageFun(member);

apfun.Return += new ReturnEventHandler<Boolean>(apfun_Return);

NavigationService.Navigate(apfun);

 

 추가한 이벤트 핸들러에서는 이벤트 인자로 전달받은 것을 입력 인자로 넣어 OnReturn 메서드를 호출하여 자신을 호출한 곳으로 전달합니다.

 

OnReturn(e);

 

 그리고마침을 눌렀을 때에는 true를 인자로 하는 이벤트 인자를 생성하여 전달하면 되고 취소를 눌렀을 때에는 false를 인자로 하는 이벤트 인자를 생성하여 전달하세요.

 

NamePageFun.xaml.cs

using System;

using System.Windows;

using System.Windows.Navigation;

namespace Ex_마법사

{

    public partial class NamePageFun : PageFunction<bool>

    {

        Member member;

        public NamePageFun(Member member)

        {

            InitializeComponent();

            this.member = member;

        }

        private void btn_next_Click(object sender, RoutedEventArgs e)

        {

            member.Name = tbox_name.Text;

            AgePageFun apfun = new AgePageFun(member);

            apfun.Return += new ReturnEventHandler<Boolean>(apfun_Return);

            NavigationService.Navigate(apfun);

        }

        void apfun_Return(object sender, ReturnEventArgs<Boolean> e)

        {

            OnReturn(e);           

        }

        private void btn_end_Click(object sender, RoutedEventArgs e)

        {

            OnReturn(new ReturnEventArgs<bool>(true));

        }

        private void btn_cancel_Click(object sender, RoutedEventArgs e)

        {

            OnReturn(new ReturnEventArgs<bool>(false));

        }       

    }

}

 

  AgePageFun.xaml 파일에서는 앞 단계에서 입력한 이름을 화면에 나타내고 사용자로부터 나이를 입력을 받을 수 있으며 이전 단계나 다음 단계로 탐색하거나 작업을 마침 혹은 취소를 할 수 있게 화면 구성을 해야 할 것입니다여기에서도 레이아웃에 대해서는 크게 신경쓰지 않겠습니다.

 

AgePageFun.xaml

<PageFunction

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

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

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

    x:Class="탐색_종합_세트___마법사.AgePageFun"

    x:TypeArguments="sys:Boolean"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:local="clr-namespace:탐색_종합_세트___마법사"

    mc:Ignorable="d"

    d:DesignHeight="300" d:DesignWidth="300"

    KeepAlive="True" Title="단계2 - 나이 입력">

    <StackPanel>

        <TextBlock Name="tb_name" Text="이름:"/>

        <TextBlock Name="tb_mname" Background="Cyan"/>

        <TextBlock Name="tb_age" Text="나이:"/>

        <TextBox Name="tbox_age" Background="Cyan"/>

        <Button Name="btn_prev" Content="이전 단계로" Click="btn_prev_Click"/>

        <Button Name="btn_next" Content="다음 단계로" Click="btn_next_Click"/>

        <Button Name="btn_end" Content="마침" Click="btn_end_Click"/>

        <Button Name="btn_cancel" Content="취소" Click="btn_cancel_Click"/>

    </StackPanel>

</PageFunction>

 

 AgePageFun NamePageFun과 매우 유사합니다생성자 메서드에서도 전달받은 회원 개체를 멤버 필드에 저장하는 것은 같습니다다만 전달받은 회원의 이름을 화면에 표시합니다.

 

this.member = member;

tb_mname.Text = member.Name;

 

 이전 단계로 버튼을 눌렀을 때에는 NavigateionServie GoBack 메서드를 호출하면 되겠죠.

 

NavigationService.GoBack();

 

 다른 메서드들은 NamePageFun과 같습니다다만다음 단계 버튼을 누렀을 때 주소를 입력받기 위해 AddrPageFun 개체라는 것이 차이일 뿐입니다.

  

AgePageFun.xaml.cs

using System.Windows;

using System.Windows.Navigation;

namespace Ex_마법사

{

    public partial class AgePageFun : PageFunction<bool>

    {

        Member member;

        public AgePageFun(Member member)

        {

            InitializeComponent();

            this.member = member;

            tb_mname.Text = member.Name;

        }

        private void btn_prev_Click(object sender, RoutedEventArgs e)

        {

            NavigationService.GoBack();

        }

        private void btn_next_Click(object sender, RoutedEventArgs e)

        {

            member.Age = tbox_age.Text;

            AddrPageFun apfun = new AddrPageFun(member);

            apfun.Return += new ReturnEventHandler<bool>(apfun_Return);

            NavigationService.Navigate(apfun);

        }

        void apfun_Return(object sender, ReturnEventArgs<bool> e){   OnReturn(e);    }

        private void btn_end_Click(object sender, RoutedEventArgs e)

        {

            OnReturn(new ReturnEventArgs<bool>(true));

        }

        private void btn_cancel_Click(object sender, RoutedEventArgs e)

        {

            OnReturn(new ReturnEventArgs<bool>(false));

        }               

    }

}

 

 AddrPageFun.xaml 파일에서는 이미 입력받은 이름과 나이를 화면에 표시하고 주소를 입력받을 수 있고 이전 단계로 이동하거나 작업을 마치거나 취소할 수 있게 화면을 구성합니다.

 

AddPageFun.xaml

<PageFunction

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

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

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

    x:Class="Ex_마법사.AddrPageFun" x:TypeArguments="sys:Boolean"

    KeepAlive="True" Title="단계3 - 주소 입력">

  <StackPanel>

        <TextBlock Name="tb_name" Text="이름:"/>  

        <TextBlock Name="tb_mname" Background="Cyan"/>

        <TextBlock Name="tb_age" Text="나이:"/>  

        <TextBlock Name="tb_mage" Background="Cyan"/>

        <TextBlock Name="tb_addr" Text="주소:"/>  

        <TextBox Name="tbox_addr" Background="Cyan"/>     

      <Button Name="btn_prev" Content="이전 단계로" Click="btn_prev_Click"/>

        <Button Name="btn_end" Content="마침" Click="btn_end_Click"/>

        <Button Name="btn_cancel" Content="취소" Click="btn_cancel_Click"/>

  </StackPanel>

</PageFunction>

 

 AddrPageFun 개체가 하는 일도 NamePageFun 개체나 AgePageFun 개체와 유사합니다다만 마지막 단계이기 때문에 다음 단계로 탐색하는 부분은 없을 뿐입니다.

 

AddrPageFun.xaml.cs

using System.Windows;

using System.Windows.Navigation;

namespace Ex_마법사

{

    public partial class AddrPageFun : PageFunction<bool>

    {

        Member member;

        public AddrPageFun(Member member)

        {

            InitializeComponent();

            this.member = member;

            tb_mname.Text = member.Name;

            tb_mage.Text = member.Age;

        }

        private void btn_end_Click(object sender, RoutedEventArgs e)

        {

            member.Addr = tbox_addr.Text;

            OnReturn(new ReturnEventArgs<bool>(true));

        }

        private void btn_cancel_Click(object sender, RoutedEventArgs e)

        {

            OnReturn(new ReturnEventArgs<bool>(false));

        }

        private void btn_prev_Click(object sender, RoutedEventArgs e)

        {

            NavigationService.GoBack();

        }

    }

}

 

  

 이제 MemberWizard를 사용하는 부분을 작성해 봅시다먼저마법사를 실행할 수 있는 버튼과 마법사에서 실행한 결과를 화면에 표시할 수 있게 배치합시다.

 

MainWindow.xaml

<Window x:Class="탐색_종합_세트___마법사.MainWindow"

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

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

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:탐색_종합_세트___마법사"

        mc:Ignorable="d"

        Title="MainWindow" Height="350" Width="525">

    <StackPanel>

        <Button Name="btn_Add" Content="회원추가" Click="btn_Add_Click"/>

        <TextBlock Name="tb_name" Text="이름:"/>

        <TextBlock Name="tb_mname" Background="Cyan"/>

        <TextBlock Name="tb_age" Text="나이:"/>

        <TextBlock Name="tb_mage" Background="Cyan"/>

        <TextBlock Name="tb_addr" Text="주소:"/>

        <TextBlock Name="tb_maddr" Background="Cyan"/>

    </StackPanel>

 

</Window>

 

 회원 추가 버튼을 눌렀을 때에 수행할 작업은 단순히 MemberWizard 개체를 생성하고 수행하게 한 후에 반환 값이 참일 경우에는 마법사에서 수행한 정보를 화면에 표시하고 거짓일 경우에는 취소된 사실을 사용자에게 확인시켜 주면 될 것입니다.

 

MemberWizard memwizard = new MemberWizard();

if ((bool)memwizard.ShowDialog())

{
    
Member member = memwizard.MemberData;

    if (member != null)

    {

        tb_mname.Text = member.Name;

        tb_mage.Text = member.Age;

        tb_maddr.Text = member.Addr;

    }

}

else

{

    MessageBox.Show("취소되었음");

}

  

Window1.xaml.cs

using System.Windows;

namespace Ex_마법사

{

    public partial class Window1 : Window

    {

        public Window1()

        {

            InitializeComponent();

        }

        private void btn_Add_Click(object sender, RoutedEventArgs e)

        {

            MemberWizard memwizard = new MemberWizard();

            if ((bool)memwizard.ShowDialog())

            {

                Member member = memwizard.MemberData;

                if (member != null)

                {

                    tb_mname.Text = member.Name;

                    tb_mage.Text = member.Age;

                    tb_maddr.Text = member.Addr;

                }

            }

            else

            {

                MessageBox.Show("취소하였습니다.");

            }

        }

    }

}       

 

[그림 4.16] 마법사 실행 1


[그림 4.17] 마법사 실행 2

[그림 4.18] 마법사 실행 3


[그림 4.19] 마법사 실행 4


[그림 4.20] 마법사 실행 5


관련 게시글

[WPF] 4. 탐색 - 4.1.1 Page

[WPF] 4. 탐색 - 4.1.2 Hyperlink 사용하여 페이지 이동

[WPF] 4. 탐색 - 4.1.3 Frame 이용하기

[WPF] 4. 탐색 - 4.1.4 NavigationService 이용하기

[WPF] 4. 탐색 - 4.2 PageFunction을 이용한 구조적 탐색


실습 파일

탐색 종합 세트 - 마법사.zip



반응형