WPF 프로그래밍 - 8. 메인 윈도우의 ListBox Refresh 적용 실습

Soonyoung Kim·2021년 8월 17일
0

WPF 프로그래밍

목록 보기
5/5

8. 메인 윈도우의 ListBox Refresh 적용 실습

  • ListBox와 LINQ 쿼리를 이용해 간단한 데이터바인딩, 새창 띄우기, 이벤트 및 델리게이트를 통한 메인 윈도우의 ListBox Refresh 적용 실습
  • 직무타입(내근:Inner, 외근:OutSide)과 직무목록을 보여주는 두개의 ListBox 컨트롤을 사용해서 직무타입을 선택하면 Linq를 통해 해당 직무타입의 직무를 쿼리해서 하단의 ListBox에 보여주는 예제이다.
  • “직무추가” 버튼을 클릭하면 새창이 뜨고 직무를 입력 후 저장 버튼을 클릭하면 직무입력 화면이 사라지고 메인 윈도우 상단의 ListBox가 새창에서 입력한 직무타입으로 선택되면서 하단의 ListBox는 해당 직무타입의 직무목록으로 자동으로 Refresh 된다.

실습

  • 프로젝트 생성 -> 프로젝트 우클릭 -> 추가 -> 새항목 -> 코드 -> 클래스(클래스명: Duty.cs)
  • Duty.cs
using System.Collections.ObjectModel;

namespace WpfApp2
{
    // 2개의 열거형 멤버가 있는 열거형 타입
    public enum DutyType
    {
        Inner, 
        OutSide
    }

    public class Duty
    {
        private string _name; //직무명
        private DutyType _dutyType; //직무타입, 내근, 외근

        public Duty() { }
        public Duty(string name, DutyType dutyType)
        {
            _name = name;
            _dutyType = dutyType;
        }

        public string DutyName
        {
            get { return _name; }
            set
            {
                _name = value;
            }
        }
        public DutyType DutyType
        {
            get { return _dutyType; }
            set
            {
                _dutyType = value;
            }
        }
    }

    // Duties클래스는 Duty클래스를 상속
    public class Duties : ObservableCollection<Duty>
    {
        public Duties()
        {
            Add(new Duty("SALES", DutyType.OutSide));
            Add(new Duty("LOGISTICS", DutyType.OutSide));
            Add(new Duty("IT",DutyType.Inner));
            Add(new Duty("MARKETING", DutyType.Inner));
            Add(new Duty("HR", DutyType.Inner));
            Add(new Duty("PROPOTION",DutyType.OutSide));
            
        }
    }
}
  • 프로젝트 우클릭 -> 새항목 -> WPF -> 창(WPF)(창 명 : SubWindow.xaml)
  • xaml(SubWindow.xaml)
<Window x:Class="WpfApp2.SubWindow"
        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:WpfApp2"
        mc:Ignorable="d"
        Title="SubWindow" Height="230" Width="350">
        <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="40"/>
            <RowDefinition Height="40"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock FontSize="20" Grid.ColumnSpan="3" HorizontalAlignment="Center" VerticalAlignment="Center">직무 등록</TextBlock>
        <TextBlock Grid.Row="1" Margin="10" VerticalAlignment="Center">직무명</TextBlock>
        <TextBox x:Name="txtDutyName" Grid.Row="1" Margin="10" Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Center"/>
        <TextBlock Margin="10" Grid.Row="2" VerticalAlignment="Center">직무타입</TextBlock>
        <RadioButton x:Name="rdoInner" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">내근</RadioButton>
        <RadioButton x:Name="rdoOutside" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center">외근</RadioButton>
        <Button Grid.Column="1" Grid.Row="3" Width="80" HorizontalAlignment="Center" Click="Button_Click" Height="22">저장</Button>
    </Grid>
</Window>
  • xaml.cs(SubWindow.xaml.cs)
using System.Windows;
using System;


namespace WpfApp2
{
    public partial class SubWindow : Window
    {
        // 메인 윈도우의 하단 ListBox를 Refresh하기 위한 델리게이트
        // 메인 윈도우에서 직무추가 버튼을 클릭할 때 이벤트를 할당해 준다
        public Delegate UpdateActor;

        public SubWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (rdoInner.IsChecked == false && rdoOutside.IsChecked == false)
            {
                MessageBox.Show("내근 또는 외근을 선택하세요.", "항목선택");
                return;
            }

            DutyType dutyType = (rdoInner.IsChecked == true) ? DutyType.Inner : DutyType.OutSide;
            MainWindow.duties.Add(
                new Duty(txtDutyName.Text,
                dutyType
                ));

            UpdateActor.DynamicInvoke(dutyType);

            MessageBox.Show("저장OK!", "저장확인");
            this.Close();
        }
    }

}
  • xaml(MainWindow.xaml)
<Window x:Class="WpfApp2.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:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:Duties x:Key="duties"/>
        <DataTemplate x:Key="MyTemplate">
            <Border Name="border">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Row="0" Grid.Column="0" Text="Duty Name: "/>
                    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=DutyName}"/>
                    <TextBlock Grid.Row="1" Grid.Column="0" Text="DutyType: "/>
                    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=DutyType}"/>
                    <TextBlock Grid.Row="2" Grid.ColumnSpan="2"/>
                </Grid>
            </Border>
        </DataTemplate>
        <LinearGradientBrush x:Key="GrayBlueGradientBrush" StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="DarkGray" Offset="0"/>
            <GradientStop Color="#CCCCFF" Offset="0.5"/>
            <GradientStop Color="DarkGray" Offset="1"/>
        </LinearGradientBrush>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}"/>
            <Setter Property="Width" Value="80"/>
            <Setter Property="Margin" Value="10"/>
        </Style>
    </Window.Resources>
    <StackPanel>
        <Button x:Name="Add" Click="OpenNewWindow">직무 추가</Button>
        <TextBlock Margin="10,0,0,0">직무타입을 선택 하세요.</TextBlock>
        <ListBox Name="myListBox1" SelectionChanged="OnSelected" SelectedIndex="0" Margin="10,0,10,0">
            <ListBoxItem>Inner</ListBoxItem>
            <ListBoxItem>OutSide</ListBoxItem>
        </ListBox>
        <TextBlock Margin="10,10,0,-10">직무</TextBlock>
        <ListBox Width="400" Margin="10" Name="myListBox2"
                 HorizontalAlignment="Stretch"
                 ItemsSource="{Binding}"
                 ItemTemplate="{StaticResource MyTemplate}"
                 SelectionChanged="OnSelected2"/>
    </StackPanel>

</Window>
  • xaml.cs(MainWindow.xaml.cs)
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp2
{
    public partial class MainWindow : Window
    {
        internal static Duties duties = new Duties();
        public MainWindow()
        {
            InitializeComponent();
        }
        // 직무추가 버튼을 클릭 했을 때 새창을 띄움
        private void OpenNewWindow(object sender, RoutedEventArgs e)
        {
            SubWindow subWindow = new SubWindow();

            RefreshListEvent += new RefreshList(RefreshListBox);
            subWindow.UpdateActor = RefreshListEvent;
            subWindow.Show();
        }
        // 아래쪽 ListBox를 Refresh 하기위한 델리게이트 및 이벤트
        public delegate void RefreshList(DutyType dutyType);
        public event RefreshList RefreshListEvent;

        // RefreshListEvent 이벤트가 발생했을 때 호출되는 메소드
        private void RefreshListBox(DutyType dutyType)
        {
            // 내근은 SelectedIndex를 0, 외근은 SelectedIndex를 1로 설정하여
            // 상단 ListBox의 선택값을 변경 시킨다
            // 상단 ListBox의 값이 바뀜에 따라 OneSelected 이벤트 핸들러가 호출되어
            // 자동으로 아래쪽 ListBox의 값은 변경된다.
            myListBox1.SelectedItem = null;
            myListBox1.SelectedIndex = (dutyType == DutyType.Inner) ? 0 : 1;
        }

        private void OnSelected(object sender, SelectionChangedEventArgs e)
        {
            if ((sender as ListBox).SelectedItem != null)
            {
                string dutyType = ((sender as ListBox).SelectedItem as ListBoxItem).Content.ToString();

                DataContext = from duty in duties
                              where duty.DutyType.ToString() == dutyType
                              select duty;
            }
        }

       private void OnSelected2(object sender, SelectionChangedEventArgs e)
        {
            var duty = (Duty)myListBox2.SelectedItem;
            string value = duty == null ? "No Selection" : duty.ToString();

            MessageBox.Show(duty.DutyName + "::" + duty.DutyType, "선택한 직무");
        }
    }

}
profile
Sin prisa, sin pausa.

0개의 댓글