■ ListView 클래스 : 항목 드래그시 스크롤하기

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


TestProject.zip


Employee.cs

 

 

using System.Collections.Generic;

 

namespace TestProject

{

    /// <summary>

    /// 직원

    /// </summary>

    public class Employee

    {

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

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

 

        #region ID - ID

 

        /// <summary>

        /// ID

        /// </summary>

        public string ID { get; set; }

 

        #endregion

        #region 성명 - Name

 

        /// <summary>

        /// 성명

        /// </summary>

        public string Name { get; set; }

 

        #endregion

 

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

        ////////////////////////////////////////////////////////////////////////////////////////// Static

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

 

        #region 리스트 구하기 - GetList()

 

        /// <summary>

        /// 리스트 구하기

        /// </summary>

        /// <returns>리스트</returns>

        public static List<Employee> GetList()

        {

            List<Employee> list = new List<Employee>();

 

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

            {

                list.Add(new Employee { ID = "ID " + i.ToString(), Name = "직원 " + i.ToString() });

            }

 

            return list;

        }

 

        #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"

    Width="800"

    Height="600"

    Title="ListView 클래스 : 항목 드래그시 스크롤하기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Grid>

        <ListView Name="listView"

            HorizontalAlignment="Center"

            VerticalAlignment="Center"

            Width="200"

            Height="300"

            AllowDrop="True">

            <ListView.View>

                <GridView>

                    <GridViewColumn

                        Width="60"

                        Header="ID"

                        DisplayMemberBinding="{Binding ID}" />

                    <GridViewColumn

                        Width="100"

                        Header="성명"

                        DisplayMemberBinding="{Binding Name}" />

                </GridView>

            </ListView.View>

        </ListView>

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System.Windows;

using System.Windows.Input;

using System.Windows.Controls;

using System.Windows.Media;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

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

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

 

        #region Field

 

        /// <summary>

        /// 데이터 포맷

        /// </summary>

        private const string DATA_FORMAT = "EmployeeDataFormat";

 

        /// <summary>

        /// 드래그 여부

        /// </summary>

        private bool isDragging = false;

 

        /// <summary>

        /// 드래그 인덱스

        /// </summary>

        private int dragIndex = -1;

 

        #endregion

 

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

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

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

 

            foreach(Employee employee in Employee.GetList())

            {

                this.listView.Items.Add(employee);

            }

 

            this.listView.PreviewMouseLeftButtonDown += listView_PreviewMouseLeftButtonDown;

            this.listView.PreviewMouseMove           += listView_PreviewMouseMove;

            this.listView.Drop                       += listView_Drop;

            this.listView.DragOver                   += listView_DragOver;

        }

 

        #endregion

 

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

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

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

 

        #region 리스트 뷰 마우스 왼쪽 버튼 DOWN PREVIEW 처리하기 - listView_PreviewMouseLeftButtonDown(sender, e)

 

        /// <summary>

        /// 리스트 뷰 마우스 왼쪽 버튼 DOWN PREVIEW 처리하기

        /// </summary>

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

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

        private void listView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            ListView listView = sender as ListView;

 

            Point mousePoint = e.GetPosition(listView);

 

            IInputElement inputElement = listView.InputHitTest(mousePoint);

 

            ListViewItem item = FindAncestor<ListViewItem>(inputElement as DependencyObject);

 

            if(item != null)

            {

                this.isDragging = true;

            }

        }

 

        #endregion

        #region 리스트 뷰 마우스 이동시 PREVIEW 처리하기 - listView_PreviewMouseMove(sender, e)

 

        /// <summary>

        /// 리스트 뷰 마우스 이동시 PREVIEW 처리하기

        /// </summary>

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

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

        private void listView_PreviewMouseMove(object sender, MouseEventArgs e)

        {

            if(this.isDragging && e.LeftButton == MouseButtonState.Pressed)

            {

                ListView listView = sender as ListView;

 

                ListViewItem listViewItem = FindAncestor<ListViewItem>(e.OriginalSource as DependencyObject);

 

                if(listViewItem == null)

                {

                    return;

                }

 

                this.dragIndex = listView.Items.IndexOf(listViewItem.Content);

 

                DataObject dataObject = new DataObject(DATA_FORMAT, listViewItem.Content);

 

                DragDrop.DoDragDrop(listViewItem, dataObject, DragDropEffects.Move);

            }

        }

 

        #endregion

        #region 리스트 뷰 DROP 처리하기 - listView_Drop(sender, e)

 

        /// <summary>

        /// 리스트 뷰 DROP 처리하기

        /// </summary>

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

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

        private void listView_Drop(object sender, DragEventArgs e)

        {

            if(e.Data.GetDataPresent(DATA_FORMAT))

            {

                ListView listView = sender as ListView;

 

                Point mousePoint = e.GetPosition(listView);

 

                IInputElement inputElement = listView.InputHitTest(mousePoint);

 

                ListViewItem item = FindAncestor<ListViewItem>(inputElement as DependencyObject);

 

                int itemIndex = -1;

 

                if(item == null)

                {

                    itemIndex = listView.Items.Count - 1;

                }

                else

                {

                    itemIndex = listView.Items.IndexOf(item.Content);

                }

 

                object content = e.Data.GetData(DATA_FORMAT);

 

                listView.Items.RemoveAt(dragIndex);

 

                if((dragIndex < itemIndex) && (item != null))

                {

                    itemIndex--;

                }

 

                listView.Items.Insert(itemIndex, content);

 

                listView.Items.Refresh();

 

                this.dragIndex = -1;

 

                this.isDragging = false;

            }

        }

 

        #endregion

        #region 리스트 뷰 DRAG OVER 처리하기 - listView_DragOver(sender, e)

 

        /// <summary>

        /// 리스트 뷰 DRAG OVER 처리하기

        /// </summary>

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

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

        private void listView_DragOver(object sender, DragEventArgs e)

        {

            ListView listView = sender as ListView;

 

            ScrollViewer scrollViewer = FindChild<ScrollViewer>(listView);

 

            double tolerance = 10;

            double mouseY    = e.GetPosition(listView).Y;

            double offset    = 1;

 

            if(mouseY < tolerance)

            {

                scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - offset);

            }

            else if(mouseY > listView.ActualHeight - tolerance)

            {

                scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);

            }

        }

 

        #endregion

 

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

 

        #region 조상 찾기 - FindAncestor<TAncestor>(dependencyObject)

 

        /// <summary>

        /// 조상 찾기

        /// </summary>

        /// <typeparam name="TAncestor">조상 타입</typeparam>

        /// <param name="dependencyObject">의존 객체</param>

        /// <returns>조상 객체</returns>

        private static TAncestor FindAncestor<TAncestor>(DependencyObject dependencyObject) where TAncestor : DependencyObject

        {

            DependencyObject current = dependencyObject;

 

            do

            {

                if(current is TAncestor)

                {

                    return (TAncestor)current;

                }

 

                current = VisualTreeHelper.GetParent(current);

            }

            while(current != null);

 

            return null;

        }

 

        #endregion

        #region 자식 찾기 - FindChild<TChilde>(dependencyObject)

 

        /// <summary>

        /// 자식 찾기

        /// </summary>

        /// <typeparam name="TChild">자식 타입</typeparam>

        /// <param name="dependencyObject">의존 객체</param>

        /// <returns>자식 객체</returns>

        private static TChild FindChild<TChild>(DependencyObject dependencyObject) where TChild : DependencyObject

        {

            int childCount = VisualTreeHelper.GetChildrenCount(dependencyObject);

 

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

            {

                DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, i);

 

                if(child != null && child is TChild)

                {

                    return (TChild)child;

                }

                else

                {

                    TChild grandChild = FindChild<TChild>(child);

 

                    if(grandChild != null)

                    {

                        return grandChild;

                    }

                }

            }

 

            return null;

        }

 

        #endregion

    }

}

 

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

Posted by 사용자 icodebroker
TAG

댓글을 달아 주세요