반응형

찰스 페졸드의 WPF 를 읽으면서 정리한 폰트 선택 다이얼로그 박스(ChooseFont) 소스.

WPF에서 기본으로 제공되지 않는 폰트 선택 다이얼로그 박스를 구현한 소스.

이 소스를 기반으로 좀 더 미려한 폰트 선택 다이얼로그 박스를 만들 수 있을 것이다.

 

[ChooseFont.cs 파일]

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace ChooseFont
{
    public class ChooseFont : Window
    {
        [STAThread]
        public static void Main()
        {
            Application app = new Application();
            app.Run(new ChooseFont());
        }

        public ChooseFont()
        {
            Title = "Choose Font";

            Button btn = new Button();
            btn.Content = Title;
            btn.HorizontalAlignment = HorizontalAlignment.Center;
            btn.VerticalAlignment = VerticalAlignment.Center;
            btn.Click += ButtonOnClick;
            Content = btn;
        }

        void ButtonOnClick(object sender, RoutedEventArgs args)
        {
            FontDialog dlg = new FontDialog();
            dlg.Owner = this;

            //윈도우의 폰트 대화상자 프로퍼티를 설정
            dlg.Typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
            dlg.FontSize = FontSize;

            if (dlg.ShowDialog().GetValueOrDefault())
            {
                //폰트 대화상자에서 윈도우 프로퍼티를 설정
                FontFamily = dlg.Typeface.FontFamily;
                FontStyle = dlg.Typeface.Style;
                FontWeight = dlg.Typeface.Weight;
                FontStretch = dlg.Typeface.Stretch;
                FontSize = dlg.FaceSize;
            }
        }
    }
}

 

[ FontDialog.cs 파일]

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace ChooseFont
{
    public class FontDialog : Window
    {
        TextBoxWithLister boxFamily, boxStyle, boxWeight, boxStretch, boxSize;
        Label lblDisplay;
        bool isUpdateSuppressed = true;

        //Public 프로퍼티
        public Typeface Typeface
        {
            set
            {
                if (boxFamily.Contains(value.FontFamily))
                    boxFamily.SelectedItem = value.FontFamily;
                else
                    boxFamily.SelectedIndex = 0;

                if (boxStyle.Contains(value.Style))
                    boxStyle.SelectedItem = value.Style;
                else
                    boxStyle.SelectedIndex = 0;

                if (boxWeight.Contains(value.Weight))
                    boxWeight.SelectedItem = value.Weight;
                else
                    boxWeight.SelectedIndex = 0;

                if (boxStretch.Contains(value.Stretch))
                    boxStretch.SelectedItem = value.Stretch;
                else
                    boxStretch.SelectedIndex = 0;
            }
            get
            {
                return new Typeface((FontFamily)boxFamily.SelectedItem, (FontStyle)boxStyle.SelectedItem,
                                    (FontWeight)boxWeight.SelectedItem, (FontStretch)boxStretch.SelectedItem);
            }
        }
        public double FaceSize
        {
            set
            {
                double size = 0.75 * value;
                boxSize.Text = size.ToString();

                if (!boxSize.Contains(size)) boxSize.Insert(0, size);

                boxSize.SelectedItem = size;
            }
            get
            {
                double size;

                if (!Double.TryParse(boxSize.Text, out size)) size = 8.25;

                return size / 0.75;
            }
        }

        //생성자
        public FontDialog()
        {
            Title = "Font";
            ShowInTaskbar = false;
            WindowStyle = WindowStyle.ToolWindow;
            WindowStartupLocation = WindowStartupLocation.CenterOwner;
            SizeToContent = SizeToContent.WidthAndHeight;
            ResizeMode = ResizeMode.NoResize;

            //윈도우 Content를 위해 3개 행을 가진 Grid를 생성
            Grid gridMain = new Grid();
            Content = gridMain;

            //TextBoxWithLister 컨트롤을 위한 행
            RowDefinition rowDef = new RowDefinition();
            rowDef.Height = new GridLength(200, GridUnitType.Pixel);
            gridMain.RowDefinitions.Add(rowDef);

            //샘플 텍스트를 위한 행
            rowDef = new RowDefinition();
            rowDef.Height = new GridLength(150, GridUnitType.Pixel);
            gridMain.RowDefinitions.Add(rowDef);

            //버튼을 위한 행
            rowDef = new RowDefinition();
            rowDef.Height = GridLength.Auto;
            gridMain.RowDefinitions.Add(rowDef);

            //메인 Grid를 위한 행
            ColumnDefinition colDef = new ColumnDefinition();
            colDef.Width = new GridLength(650, GridUnitType.Pixel);
            gridMain.ColumnDefinitions.Add(colDef);

            //TextBoxWithLister 컨트롤을 위해 2개 행과 5개 열을 가진 Grid를 생성
            Grid gridBoxes = new Grid();
            gridMain.Children.Add(gridBoxes);

            //라벨을 위한 행
            rowDef = new RowDefinition();
            rowDef.Height = GridLength.Auto;
            gridBoxes.RowDefinitions.Add(rowDef);

            //EditBoxWithLister 컨트롤을 위한 행
            rowDef = new RowDefinition();
            rowDef.Height = new GridLength(100, GridUnitType.Star);
            gridBoxes.RowDefinitions.Add(rowDef);

            //폰트 패밀리를 위한 첫 번째 열
            colDef = new ColumnDefinition();
            colDef.Width = new GridLength(175, GridUnitType.Star);
            gridBoxes.ColumnDefinitions.Add(colDef);

            //폰트 스타일을 위한 두 번째 열
            colDef = new ColumnDefinition();
            colDef.Width = new GridLength(100, GridUnitType.Star);
            gridBoxes.ColumnDefinitions.Add(colDef);

            //폰트 웨이트를 위한 세 번째 열
            colDef = new ColumnDefinition();
            colDef.Width = new GridLength(175, GridUnitType.Star);
            gridBoxes.ColumnDefinitions.Add(colDef);

            //폰트 스트레치를 위한 네 번째 열
            colDef = new ColumnDefinition();
            colDef.Width = new GridLength(100, GridUnitType.Star);
            gridBoxes.ColumnDefinitions.Add(colDef);

            //크기를 위한 다섯 번째 열
            colDef = new ColumnDefinition();
            colDef.Width = new GridLength(75, GridUnitType.Star);
            gridBoxes.ColumnDefinitions.Add(colDef);

            //TextBoxWithLister 컨트롤과 폰트 패밀리 레이블 생성
            Label lbl = new Label();
            lbl.Content = "Font Family";
            lbl.Margin = new Thickness(12, 12, 12, 0);
            gridBoxes.Children.Add(lbl);
            Grid.SetRow(lbl, 0);
            Grid.SetColumn(lbl, 0);

            boxFamily = new TextBoxWithLister();
            boxFamily.IsReadOnly = true;
            boxFamily.Margin = new Thickness(12, 0, 12, 12);
            gridBoxes.Children.Add(boxFamily);
            Grid.SetRow(boxFamily, 1);
            Grid.SetColumn(boxFamily, 0);

            //TextBoxWithLister 컨트롤과 폰트 스타일 레이블 생성
            lbl = new Label();
            lbl.Content = "Style";
            lbl.Margin = new Thickness(12, 12, 12, 0);
            gridBoxes.Children.Add(lbl);
            Grid.SetRow(lbl, 0);
            Grid.SetColumn(lbl, 1);

            boxStyle = new TextBoxWithLister();
            boxStyle.IsReadOnly = true;
            boxStyle.Margin = new Thickness(12, 0, 12, 12);
            gridBoxes.Children.Add(boxStyle);
            Grid.SetRow(boxStyle, 1);
            Grid.SetColumn(boxStyle, 1);

            //TextBoxWithLister 컨트롤과 폰트 웨이트 레이블 생성
            lbl = new Label();
            lbl.Content = "Weight";
            lbl.Margin = new Thickness(12, 12, 12, 0);
            gridBoxes.Children.Add(lbl);
            Grid.SetRow(lbl, 0);
            Grid.SetColumn(lbl, 2);

            boxWeight = new TextBoxWithLister();
            boxWeight.IsReadOnly = true;
            boxWeight.Margin = new Thickness(12, 0, 12, 12);
            gridBoxes.Children.Add(boxWeight);
            Grid.SetRow(boxWeight, 1);
            Grid.SetColumn(boxWeight, 2);

            //TextBoxWithLister 컨트롤과 폰트 스트레치 레이블 생성
            lbl = new Label();
            lbl.Content = "Stretch";
            lbl.Margin = new Thickness(12, 12, 12, 0);
            gridBoxes.Children.Add(lbl);
            Grid.SetRow(lbl, 0);
            Grid.SetColumn(lbl, 3);

            boxStretch = new TextBoxWithLister();
            boxStretch.IsReadOnly = true;
            boxStretch.Margin = new Thickness(12, 0, 12, 12);
            gridBoxes.Children.Add(boxStretch);
            Grid.SetRow(boxStretch, 1);
            Grid.SetColumn(boxStretch, 3);

            //TextBoxWithLister 컨트롤과 크기 레이블 생성
            lbl = new Label();
            lbl.Content = "Size";
            lbl.Margin = new Thickness(12, 12, 12, 0);
            gridBoxes.Children.Add(lbl);
            Grid.SetRow(lbl, 0);
            Grid.SetColumn(lbl, 4);

            boxSize = new TextBoxWithLister();
            boxSize.Margin = new Thickness(12, 0, 12, 12);
            gridBoxes.Children.Add(boxSize);
            Grid.SetRow(boxSize, 1);
            Grid.SetColumn(boxSize, 4);

            //샘플 텍스트를 보여주기 위한 레이블 생성
            lblDisplay = new Label();
            lblDisplay.Content = "AaBbCc XxYyZz 012345";
            lblDisplay.HorizontalContentAlignment = HorizontalAlignment.Center;
            lblDisplay.VerticalContentAlignment = VerticalAlignment.Center;
            gridMain.Children.Add(lblDisplay);
            Grid.SetRow(lblDisplay, 1);

            //버튼을 위해 5개의 열을 가진 Grid를 생성
            Grid gridButtons = new Grid();
            gridMain.Children.Add(gridButtons);
            Grid.SetRow(gridButtons, 2);

            for (int i = 0; i < 5; i++)
            {
                gridButtons.ColumnDefinitions.Add(new ColumnDefinition());
            }

            //OK 버튼
            Button btn = new Button();
            btn.Content = "OK";
            btn.IsDefault = true;
            btn.HorizontalAlignment = HorizontalAlignment.Center;
            btn.MinWidth = 60;
            btn.Margin = new Thickness(12);
            btn.Click += OkOnClick;
            gridButtons.Children.Add(btn);
            Grid.SetColumn(btn, 1);

            //Cancel 버튼
            btn = new Button();
            btn.Content = "Cancel";
            btn.IsCancel = true;
            btn.HorizontalAlignment = HorizontalAlignment.Center;
            btn.MinWidth = 60;
            btn.Margin = new Thickness(12);
            gridButtons.Children.Add(btn);
            Grid.SetColumn(btn, 3);

            //시스템 폰트 패밀리로 폰트 패밀리 박스를 초기화
            foreach (FontFamily fam in Fonts.SystemFontFamilies)
            {
                boxFamily.Add(fam);
            }

            //폰트 크기 박스를 초기화
            double[] ptSizes = new double[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 };
            foreach (double ptSize in ptSizes)
            {
                boxSize.Add(ptSize);
            }

            //이벤트 핸들러를 설정
            boxFamily.SelectionChanged += FamilyOnSelectionChanged;
            boxStyle.SelectionChanged += StyleOnSelectionChanged;
            boxWeight.SelectionChanged += StyleOnSelectionChanged;
            boxStretch.SelectionChanged += StyleOnSelectionChanged;
            boxSize.TextChanged += SizeOnTextChanged;

            //윈도우 프로퍼티를 기반으로 선택 값을 설정
            //(이 부분은 프로퍼티가 설정되면 오버라이딩됨)
            Typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);

            FaceSize = FontSize;

            //키보드 포커스를 설정
            boxFamily.Focus();

            //샘플 텍스트를 수정할 수 있게 함
            isUpdateSuppressed = false;
            UpdateSample();
        }

        //폰트 패밀리 박스에 대한 SelectionChanged 이벤트 핸들러
        void FamilyOnSelectionChanged(object sender, EventArgs args)
        {
            //선택한 패밀리를 구함
            FontFamily fontFamily = (FontFamily)boxFamily.SelectedItem;

            //이전 스타일, 웨이트, 스트레치를 저장
            //이 값은 이 메소드가 처음 불릴 때는 null
            FontStyle? fntStyPrevious = (FontStyle?) boxStyle.SelectedItem;
            FontWeight? fntWtPrevious = (FontWeight?) boxWeight.SelectedItem;
            FontStretch? fntStrPrevious = (FontStretch?) boxStretch.SelectedItem;

            //샘플이 보이지 않게 함
            isUpdateSuppressed = true;

            //스타일, 웨이트, 스트레치 박스를 지움
            boxStyle.Clear();
            boxWeight.Clear();
            boxStretch.Clear();

            //선택된 폰트 패밀리의 typefaces에 대해서 루프를 수행
            foreach (FamilyTypeface ftf in fontFamily.FamilyTypefaces)
            {
                //boxStyle에 스타일을 추가(Normal이 가장 상위에 위치)
                if (!boxStyle.Contains(ftf.Style))
                {
                    if (ftf.Style == FontStyles.Normal)
                        boxStyle.Insert(0, ftf.Style);
                    else
                        boxStyle.Add(ftf.Style);
                }
                //boxWeight에 웨이트를 추가(Normal이 가장 상위에 위치)
                if (!boxWeight.Contains(ftf.Weight))
                {
                    if (ftf.Weight == FontWeights.Normal)
                        boxWeight.Insert(0, ftf.Weight);
                    else
                        boxWeight.Add(ftf.Weight);
                }
                //boxStretch에 스트레치를 추가(Normal이 가장 상위에 위치)
                if (!boxStretch.Contains(ftf.Stretch))
                {
                    if (ftf.Stretch == FontStretches.Normal)
                        boxStretch.Insert(0, ftf.Stretch);
                    else
                        boxStretch.Add(ftf.Stretch);
                }
            }

            //boxStyle에 선택 항목을 설정
            if (boxStyle.Contains(fntStyPrevious))
                boxStyle.SelectedItem = fntStyPrevious;
            else
                boxStyle.SelectedIndex = 0;

            //boxWeight에 선택 항목을 설정
            if (boxWeight.Contains(fntWtPrevious))
                boxWeight.SelectedItem = fntWtPrevious;
            else
                boxWeight.SelectedIndex = 0;

            //boxStretch에 선택 항목을 설정
            if (boxStretch.Contains(fntStrPrevious))
                boxStretch.SelectedItem = fntStrPrevious;
            else
                boxStretch.SelectedIndex = 0;

            //샘플 수정이 가능하게 하고 샘플을 갱신
            isUpdateSuppressed = false;
            UpdateSample();
        }

        //스타일, 웨이트, 스트레치 박스에 대한 SelectionChanged 이벤트 핸들러
        void StyleOnSelectionChanged(object sender, EventArgs args)
        {
            UpdateSample();
        }

        //크기 박스에 대한 TextChanged 이벤트 핸들러
        void SizeOnTextChanged(object sender, TextChangedEventArgs args)
        {
            UpdateSample();
        }

        //샘플 텍스트 갱신
        void UpdateSample()
        {
            if (isUpdateSuppressed) return;

            lblDisplay.FontFamily = (FontFamily)boxFamily.SelectedItem;
            lblDisplay.FontStyle = (FontStyle)boxStyle.SelectedItem;
            lblDisplay.FontWeight = (FontWeight)boxWeight.SelectedItem;
            lblDisplay.FontStretch = (FontStretch)boxStretch.SelectedItem;

            double size;

            if (!Double.TryParse(boxSize.Text, out size))
                size = 8.25;

            lblDisplay.FontSize = size / 0.75;
        }

        //OK 버튼을 누르면 대화상자를 종료
        void OkOnClick(object sender, RoutedEventArgs args)
        {
            DialogResult = true;
        }
    }
}

 

[TextBoxWithLister.cs 파일]

using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace ChooseFont
{
    public class TextBoxWithLister : ContentControl
    {
        TextBox txtBox;
        Lister lister;
        bool isReadOnly;

        //Public 이벤트
        public event EventHandler SelectionChanged;
        public event TextChangedEventHandler TextChanged;

        //생성자
        public TextBoxWithLister()
        {
            //윈도우 Content를 위해 DockPanel 생성
            DockPanel dock = new DockPanel();
            Content = dock;

            //상단에 위치할 텍스트 박스
            txtBox = new TextBox();
            txtBox.TextChanged += TextBoxOnTextChanged;
            dock.Children.Add(txtBox);
            DockPanel.SetDock(txtBox, Dock.Top);

            //DockPanel의 나머지에 Lister를 추가
            lister = new Lister();
            lister.SelectionChanged += ListerOnSelectionChanged;
            dock.Children.Add(lister);
        }

        //텍스트 박스 항목과 관련된 Public 프로퍼티
        public string Text
        {
            get { return txtBox.Text; }
            set { txtBox.Text = value; }
        }
        public bool IsReadOnly
        {
            get { return isReadOnly; }
            set { isReadOnly = value; }
        }

        //Lister 요소의 다른 public 프로퍼티 인터페이스
        public object SelectedItem
        {
            set
            {
                lister.SelectedItem = value;

                if (lister.SelectedItem != null)
                    txtBox.Text = lister.SelectedItem.ToString();
                else
                    txtBox.Text = "";
            }
            get
            {
                return lister.SelectedItem;
            }
        }
        public int SelectedIndex
        {
            set
            {
                lister.SelectedIndex = value;

                if (lister.SelectedIndex == -1)
                    txtBox.Text = "";
                else
                    txtBox.Text = lister.SelectedItem.ToString();
            }
            get
            {
                return lister.SelectedIndex;
            }
        }
        public void Add(object obj)
        {
            lister.Add(obj);
        }
        public void Insert(int index, object obj)
        {
            lister.Insert(index, obj);
        }
        public void Clear()
        {
            lister.Clear();
        }
        public bool Contains(object obj)
        {
            return lister.Contains(obj);
        }

        //마우스를 클릭하면 키보드 포커스를 설정
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
            Focus();
        }

        //키보드가 포커스를 갖게 되면 텍스트 박스에 포커스를 설정
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnGotKeyboardFocus(e);

            if (e.NewFocus == this)
            {
                txtBox.Focus();
                if (SelectedIndex == -1 && lister.Count > 0)
                    SelectedIndex = 0;
            }
        }

        //첫 문자를 입력하면 이 값을 GoToLetter 메소드로 넘김
        protected override void OnPreviewTextInput(TextCompositionEventArgs e)
        {
            base.OnPreviewTextInput(e);

            if (IsReadOnly)
            {
                lister.GoToLetter(e.Text[0]);
                e.Handled = true;
            }
        }

        //선택 항목을 변경하기 위해 커서 이동키를 처리
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);

            if (SelectedIndex == -1) return;

            switch(e.Key)
            {
                case Key.Home:
                    if (lister.Count > 0) SelectedIndex = 0;
                    break;
                case Key.End:
                    if (lister.Count > 0) SelectedIndex = lister.Count - 1;
                    break;
                case Key.Up:
                    if (SelectedIndex > 0) SelectedIndex--;
                    break;
                case Key.Down:
                    if (SelectedIndex < lister.Count - 1) SelectedIndex++;
                    break;
                case Key.PageUp:
                    lister.PageUp();
                    break;
                case Key.PageDown:
                    lister.PageDown();
                    break;
                default:
                    return;
            }
            e.Handled = true;
        }

        //이벤트 핸들러와 트리거
        void ListerOnSelectionChanged(object sender, EventArgs args)
        {
            if (SelectedIndex == -1)
                txtBox.Text = "";
            else
                txtBox.Text = lister.SelectedItem.ToString();

            OnSelectionChanged(args);
        }

        void TextBoxOnTextChanged(object sender, TextChangedEventArgs args)
        {
            if (TextChanged != null) TextChanged(this, args);
        }
        protected virtual void OnSelectionChanged(EventArgs args)
        {
            if (SelectionChanged != null) SelectionChanged(this, args);
        }
    }
}

 

[Lister.cs 파일]

using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace ChooseFont
{
    public class Lister : ContentControl
    {
        ScrollViewer scroll;
        StackPanel stack;
        ArrayList list = new ArrayList();
        int indexSelected = -1;

        //Public 이벤트
        public event EventHandler SelectionChanged;

        //생성자
        public Lister()
        {
            Focusable = false;

            //윈도우의 Content를 ContentControl의 Border로 설정
            Border border = new Border();
            border.BorderThickness = new Thickness(1);
            border.BorderBrush = SystemColors.ActiveBorderBrush;
            border.Background = SystemColors.WindowBrush;
            Content = border;

            //border의 자식으로 ScrollViewer 생성
            scroll = new ScrollViewer();
            scroll.Focusable = false;
            scroll.Padding = new Thickness(2, 0, 0, 0);
            border.Child = scroll;

            //ScrollViewer의 Content로 스택 패널을 생성
            stack = new StackPanel();
            scroll.Content = stack;

            //마우스 왼쪽 버튼에 대한 핸들러를 연결
            AddHandler(TextBlock.MouseLeftButtonDownEvent, new MouseButtonEventHandler(TextBlockOnMouseLeftButtonDown));

            Loaded += OnLoaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            //Lister가 처음 보여질 때 뷰에 선택된 항목을 스크롤
            ScrollIntoView();
        }

        //Lister에 항목을 추가하고, 삽입하는 Public 메소드
        public void Add(object obj)
        {
            list.Add(obj);
            TextBlock txtBlk = new TextBlock();
            txtBlk.Text = obj.ToString();
            stack.Children.Add(txtBlk);
        }

        public void Insert(int index, object obj)
        {
            list.Insert(index, obj);
            TextBlock txtBlk = new TextBlock();
            txtBlk.Text = obj.ToString();
            stack.Children.Insert(index, txtBlk);
        }

        public void Clear()
        {
            SelectedIndex = -1;
            stack.Children.Clear();
            list.Clear();
        }

        public bool Contains(object obj)
        {
            return list.Contains(obj);
        }

        public int Count
        {
            get { return list.Count; }
        }

        //입력한 문자에 따라 항목이 선택되게 하기 위해 호출되는 메소드
        public void GoToLetter(char ch)
        {
            int offset = SelectedIndex + 1;

            for (int i = 0; i < Count; i++)
            {
                int index = (i + offset) % Count;

                if (Char.ToUpper(ch) == Char.ToUpper(list[index].ToString()[0]))
                {
                    SelectedIndex = index;
                    break;
                }
            }
        }

        //선택바를 출력하기 위한 SelectedIndex 프로퍼티
        public int SelectedIndex
        {
            set
            {
                if (value < -1 || value >= Count)
                    throw new ArgumentOutOfRangeException("SelectedIndex");

                if (value == indexSelected) return;

                if (indexSelected != -1)
                {
                    TextBlock txtBlk = stack.Children[indexSelected] as TextBlock;
                    txtBlk.Background = SystemColors.WindowBrush;
                    txtBlk.Foreground = SystemColors.WindowTextBrush;
                }

                indexSelected = value;

                if (indexSelected > -1)
                {
                    TextBlock txtBlk = stack.Children[indexSelected] as TextBlock;
                    txtBlk.Background = SystemColors.HighlightBrush;
                    txtBlk.Foreground = SystemColors.HighlightTextBrush;
                }
                ScrollIntoView();

                //SelectionChanged 이벤트 트리거
                OnSelectionChanged(EventArgs.Empty);
            }
            get
            {
                return indexSelected;
            }
        }

        //SelectionItem 프로퍼티는 SelectedIndex를 이용
        public object SelectedItem
        {
            set
            {
                SelectedIndex = list.IndexOf(value);
            }
            get
            {
                if (SelectedIndex > -1) return list[SelectedIndex];
                return null;
            }
        }

        //리스트에서 페이지 업, 페이지 다운하는 Public 메소드
        public void PageUp()
        {
            if (SelectedIndex == -1 || Count == 0) return;

            int index = SelectedIndex - (int)(Count * scroll.ViewportHeight / scroll.ExtentHeight);
            if (index < 0) index = 0;

            SelectedIndex = index;
        }

        public void PageDown()
        {
            if (SelectedIndex == -1 || Count == 0) return;

            int index = SelectedIndex + (int)(Count * scroll.ViewportHeight / scroll.ExtentHeight);
            if (index > Count - 1) index = Count - 1;

            SelectedIndex = index;
        }

        //뷰에서 선택 항목을 스크롤하는 Private 메소드
        void ScrollIntoView()
        {
            if (Count == 0 || SelectedIndex == -1 || scroll.ViewportHeight > scroll.ExtentHeight) return;

            double heightPerItem = scroll.ExtentHeight / Count;
            double offsetItemTop = SelectedIndex * heightPerItem;
            double offsetItemBot = (SelectedIndex + 1) * heightPerItem;

            if (offsetItemTop < scroll.VerticalOffset) scroll.ScrollToVerticalOffset(offsetItemTop);
            else if (offsetItemBot > scroll.VerticalOffset + scroll.ViewportHeight)
            {
                scroll.ScrollToVerticalOffset(scroll.VerticalOffset + offsetItemBot - scroll.VerticalOffset - scroll.ViewportHeight);
            }
        }

        //이벤트 핸들러와 트리거
        void TextBlockOnMouseLeftButtonDown(object sender, MouseButtonEventArgs args)
        {
            if (args.Source is TextBlock)
                SelectedIndex = stack.Children.IndexOf(args.Source as TextBlock);
        }

        protected virtual void OnSelectionChanged(EventArgs args)
        {
            if (SelectionChanged != null)
                SelectionChanged(this, args);
        }
    }
}

 

반응형

+ Recent posts