첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

728x90
반응형

■ ContentControl 클래스 : 리스트 컨트롤 만들기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


ListControl.cs

 

 

using System;

using System.Collections;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Input;

 

namespace TestProject

{

    /// <summary>

    /// 리스트 컨트롤

    /// </summary>

    public class ListControl : ContentControl

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Declaration

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region Event

 

        /// <summary>

        /// 선택 변경시

        /// </summary>

        public event EventHandler SelectionChanged;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 스크롤 뷰어

        /// </summary>

        private ScrollViewer scrollViewer;

 

        /// <summary>

        /// 스택 패널

        /// </summary>

        private StackPanel stackPanel;

 

        /// <summary>

        /// 배열 리스트

        /// </summary>

        private ArrayList arrayList = new ArrayList();

 

        /// <summary>

        /// 선택 인덱스

        /// </summary>

        private int selectedIndex = -1;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 수 - Count

 

        /// <summary>

        ///

        /// </summary>

        public int Count

        {

            get

            {

                return this.arrayList.Count;

            }

        }

 

        #endregion

        #region 선택 인덱스 - SelectedIndex

 

        /// <summary>

        /// 선택 인덱스

        /// </summary>

        public int SelectedIndex

        {

            set

            {

                if(value < -1 || value >= Count)

                {

                    throw new ArgumentOutOfRangeException("SelectedIndex");

                }

 

                if(value == this.selectedIndex)

                {

                    return;

                }

 

                if(this.selectedIndex != -1)

                {

                    TextBlock textBlock = this.stackPanel.Children[this.selectedIndex] as TextBlock;

 

                    textBlock.Background = SystemColors.WindowBrush;

                    textBlock.Foreground = SystemColors.WindowTextBrush;

                }

 

                this.selectedIndex = value;

 

                if(this.selectedIndex > -1)

                {

                    TextBlock textBlock = this.stackPanel.Children[this.selectedIndex] as TextBlock;

 

                    textBlock.Background = SystemColors.HighlightBrush;

                    textBlock.Foreground = SystemColors.HighlightTextBrush;

                }

 

                ScrollIntoView();

 

                OnSelectionChanged(EventArgs.Empty);

            }

            get

            {

                return this.selectedIndex;

            }

        }

 

        #endregion

        #region 선택 항목 - SelectedItem

 

        /// <summary>

        /// 선택 항목

        /// </summary>

        public object SelectedItem

        {

            set

            {

                SelectedIndex = this.arrayList.IndexOf(value);

            }

            get

            {

                if(SelectedIndex > -1)

                {

                    return this.arrayList[SelectedIndex];

                }

 

                return null;

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - ListControl()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public ListControl()

        {

            Focusable = false;

 

            Border border = new Border();

 

            border.BorderThickness = new Thickness(1);

            border.BorderBrush     = SystemColors.ActiveBorderBrush;

            border.Background      = SystemColors.WindowBrush;

 

            Content = border;

 

            this.scrollViewer = new ScrollViewer();

 

            this.scrollViewer.Focusable = false;

            this.scrollViewer.Padding   = new Thickness(2, 0, 0, 0);

 

            border.Child = this.scrollViewer;

 

            this.stackPanel = new StackPanel();

 

            this.scrollViewer.Content = this.stackPanel;

 

            AddHandler

            (

                TextBlock.MouseLeftButtonDownEvent,

                new MouseButtonEventHandler(textBlock_MouseLeftButtonDown)

            );

 

            Loaded += ListControl_Loaded;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Public

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 지우기 - Clear()

 

        /// <summary>

        /// 지우기

        /// </summary>

        public void Clear()

        {

            SelectedIndex = -1;

 

            this.stackPanel.Children.Clear();

 

            this.arrayList.Clear();

        }

 

        #endregion

        #region 추가하기 - Add(value)

 

        /// <summary>

        /// 추가하기

        /// </summary>

        /// <param name="value"></param>

        public void Add(object value)

        {

            this.arrayList.Add(value);

 

            TextBlock textBlock = new TextBlock();

 

            textBlock.Text = value.ToString();

 

            this.stackPanel.Children.Add(textBlock);

        }

 

        #endregion

        #region 삽입하기 - Insert(index, value)

 

        /// <summary>

        /// 삽입하기

        /// </summary>

        /// <param name="index">인덱스</param>

        /// <param name="value"></param>

        public void Insert(int index, object value)

        {

            this.arrayList.Insert(index, value);

 

            TextBlock textBlock = new TextBlock();

 

            textBlock.Text = value.ToString();

 

            this.stackPanel.Children.Insert(index, textBlock);

        }

 

        #endregion

        #region 포함 여부 조사하기 - Contains(value)

 

        /// <summary>

        /// 포함 여부 조사하기

        /// </summary>

        /// <param name="value"></param>

        /// <returns>포함 여부</returns>

        public bool Contains(object value)

        {

            return this.arrayList.Contains(value);

        }

 

        #endregion

        #region 글자로 이동하기 - GoToLetter(character)

 

        /// <summary>

        /// 글자로 이동하기

        /// </summary>

        /// <param name="character">문자</param>

        public void GoToLetter(char character)

        {

            int offset = SelectedIndex + 1;

 

            for(int i = 0; i < Count; i++)

            {

                int index = (i + offset) % Count;

 

                if(Char.ToUpper(character) == Char.ToUpper(this.arrayList[index].ToString()[0]))

                {

                    SelectedIndex = index;

 

                    break;

                }

            }

        }

 

        #endregion

        #region 페이지 위로 이동하기 - PageUp()

 

        /// <summary>

        /// 페이지 위로 이동하기

        /// </summary>

        public void PageUp()

        {

            if(SelectedIndex == -1 || Count == 0)

            {

                return;

            }

 

            int index = SelectedIndex - (int)(Count * this.scrollViewer.ViewportHeight / this.scrollViewer.ExtentHeight);

 

            if(index < 0)

            {

                index = 0;

            }

 

            SelectedIndex = index;

        }

 

        #endregion

        #region 페이지 아래로 이동하기 - PageDown()

 

        /// <summary>

        /// 페이지 아래로 이동하기

        /// </summary>

        public void PageDown()

        {

            if(SelectedIndex == -1 || Count == 0)

            {

                return;

            }

 

            int index = SelectedIndex + (int)(Count * this.scrollViewer.ViewportHeight / this.scrollViewer.ExtentHeight);

 

            if(index > Count - 1)

            {

                index = Count - 1;

            }

 

            SelectedIndex = index;

        }

 

        #endregion

        #region 선택 항목 보이기 - ScrollIntoView()

 

        /// <summary>

        /// 선택 항목 보이기

        /// </summary>

        public void ScrollIntoView()

        {

            if(Count == 0 || SelectedIndex == -1 || this.scrollViewer.ViewportHeight > this.scrollViewer.ExtentHeight)

            {

                return;

            }

 

            double itemHeight       = this.scrollViewer.ExtentHeight / Count;

            double itemTopOffset    = SelectedIndex * itemHeight;

            double itemBottomOffset = (SelectedIndex + 1) * itemHeight;

 

            if(itemTopOffset < this.scrollViewer.VerticalOffset)

            {

                this.scrollViewer.ScrollToVerticalOffset(itemTopOffset);

            }

            else if(itemBottomOffset > this.scrollViewer.VerticalOffset + this.scrollViewer.ViewportHeight)

            {

                this.scrollViewer.ScrollToVerticalOffset

                (

                    this.scrollViewer.VerticalOffset + itemBottomOffset - this.scrollViewer.VerticalOffset - this.scrollViewer.ViewportHeight

                );

            }

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 선택 변경시 처리하기 - OnSelectionChanged(e)

 

        /// <summary>

        /// 선택 변경시 처리하기

        /// </summary>

        /// <param name="e">이벤트 인자</param>

        protected virtual void OnSelectionChanged(EventArgs e)

        {

            if(SelectionChanged != null)

            {

                SelectionChanged(this, e);

            }

        }

 

        #endregion

 

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 리스트 컨트롤 로드시 처리하기 - ListControl_Loaded(sender, e)

 

        /// <summary>

        /// 리스트 컨트롤 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void ListControl_Loaded(object sender, RoutedEventArgs e)

        {

            ScrollIntoView();

        }

 

        #endregion

        #region 텍스트 블럭 마우스 왼쪽 버튼 DOWN 처리하기 - textBlock_MouseLeftButtonDown(sender, e)

 

        /// <summary>

        /// 텍스트 블럭 마우스 왼쪽 버튼 DOWN 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void textBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            if(e.Source is TextBlock)

            {

                SelectedIndex = this.stackPanel.Children.IndexOf(e.Source as TextBlock);

            }

        }

 

        #endregion

    }

}

 

 

MainWindow.xaml

 

 

<Window x:Class="TestProject.MainWindow"

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

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

    xmlns:local="clr-namespace:TestProject"

    Width="800"

    Height="600"

    Title="ContentControl 클래스 : 리스트 컨트롤 만들기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Grid Margin="10">

        <StackPanel

            HorizontalAlignment="Center"

            VerticalAlignment="Center">

            <local:ListControl x:Name="listControl"

                Margin="10"

                Width="200"

                Height="300" />

            <UniformGrid

                Margin="10"

                Columns="4">

                <Button Name="clearButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="지우기" />

                <Button Name="addButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="추가하기" />

                <Button Name="insertButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="삽입하기" />

                <Button Name="containsButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="포함 여부" />

                <Button Name="letterButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="글자로 이동" />

                <Button Name="pageUpButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="페이지 위" />

                <Button Name="pageDownButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="페이지 아래" />

                <Button Name="scrollButton"

                    Margin="10"

                    Width="100"

                    Height="30"

                    Content="스크롤" />

            </UniformGrid>

        </StackPanel>

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System.Windows;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

 

            this.clearButton.Click    += clearButton_Click;

            this.addButton.Click      += addButton_Click;

            this.insertButton.Click   += insertButton_Click;

            this.containsButton.Click += containsButton_Click;

            this.letterButton.Click   += letterButton_Click;

            this.pageUpButton.Click   += pageUpButton_Click;

            this.pageDownButton.Click += pageDownButton_Click;

            this.scrollButton.Click   += scrollButton_Click;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 지우기 버튼 클릭시 처리하기 - clearButton_Click(sender, e)

 

        /// <summary>

        /// 지우기 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void clearButton_Click(object sender, RoutedEventArgs e)

        {

            this.listControl.Clear();

        }

 

        #endregion

        #region 추가하기 버튼 클릭시 처리하기 - addButton_Click(sender, e)

 

        /// <summary>

        /// 추가하기 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void addButton_Click(object sender, RoutedEventArgs e)

        {

            this.listControl.Clear();

 

            for(int i = 200; i < 300; i++)

            {

                this.listControl.Add(i);

            }

        }

 

        #endregion

        #region 삽입하기 버튼 클릭시 처리하기 - insertButton_Click(sender, e)

 

        /// <summary>

        /// 삽입하기 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void insertButton_Click(object sender, RoutedEventArgs e)

        {

            for(int i = 199; i >= 100; i--)

            {

                this.listControl.Insert(0, i);

            }

        }

 

        #endregion

        #region 포함 여부 버튼 클릭시 처리하기 - containsButton_Click(sender, e)

 

        /// <summary>

        /// 포함 여부 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void containsButton_Click(object sender, RoutedEventArgs e)

        {

            bool result = this.listControl.Contains(250);

 

            MessageBox.Show("250 포함 여부 : " + result.ToString());

        }

 

        #endregion

        #region 글자로 이동 버튼 클릭시 처리하기 - containsButton_Click(sender, e)

 

        /// <summary>

        /// 글자로 이동 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void letterButton_Click(object sender, RoutedEventArgs e)

        {

            this.listControl.GoToLetter('2');

 

            this.listControl.ScrollIntoView();

        }

 

        #endregion

        #region 페이지 위 버튼 클릭시 처리하기 - pageUpButton_Click(sender, e)

 

        /// <summary>

        /// 페이지 위 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void pageUpButton_Click(object sender, RoutedEventArgs e)

        {

            this.listControl.PageUp();

        }

 

        #endregion

        #region 페이지 아래 버튼 클릭시 처리하기 - pageDownButton_Click(sender, e)

 

        /// <summary>

        /// 페이지 아래 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void pageDownButton_Click(object sender, RoutedEventArgs e)

        {

            this.listControl.PageDown();

        }

 

        #endregion

        #region 스크롤 버튼 클릭시 처리하기 - scrollButton_Click(sender, e)

 

        /// <summary>

        /// 스크롤 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void scrollButton_Click(object sender, RoutedEventArgs e)

        {

            this.listControl.SelectedIndex = this.listControl.Count - 1;

 

            this.listControl.ScrollIntoView();

        }

 

        #endregion

    }

}

 

------------------------------------------------------------------------------------------------------------------------

728x90
반응형
Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요