2010년 2월 21일 일요일

WPF OpenFileDialog

원문 : WPF OpenFileDialog





WPF OpenFileDialog



WPF 에서 OpenFileDialog 를 이용하는 방법을 알아보자. 파일을 여는 대화상자는 Windows 프로그램에서 워낙 일반적이고 자주 사용되기 때문에 언어적 차원에서 미리 구현되어 있어 사용하기만 하면 됬다. WinForm 에서도 OpenFileDialog 가 존재하는데 내부적으로는 Win32 API 를 이용한다. 그렇다면 WPF 에서는??

테스트할 WPF 데모 프로젝트를 만들자.

우선 xaml 파일에 테스트할 응용프로그램을 아래와 같이 디자인 한다.

<Grid>        <Button Content="Browse" Height="32" HorizontalAlignment="Left"
                Margin="20,12,0,0" Click="button1_Click"                Name="button1" VerticalAlignment="Top" Width
="136" />
        <Image Margin="12,70,0,20" Name="MyImage" Stretch="Fill" HorizontalAlignment="Left" Width="200" />        <ListBox Margin="263,70,46,20" Name="listBox1" /></Grid>




버튼 클릭 이벤트 핸들러를 다음과 같이 코딩해 준다.

private void button1_Click(object sender, RoutedEventArgs e)
        {
            Stream checkStream = null;
            Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();

            openFileDialog.Multiselect = false;
            //
openFileDialog.InitialDirectory = "c:\\";            //if you want filter only .txt file            //dlg.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            //if you want filter all files                        openFileDialog.Filter = "All Image Files | *.*";
            if ((bool)openFileDialog.ShowDialog())
            {
               
try                {
                    if ((checkStream = openFileDialog.OpenFile()) != null)
                    {
                       MyImage.Source = new BitmapImage(new Uri(openFileDialog.FileName, UriKind.Absolute));
                        listBox1.Items.Add(openFileDialog.FileName);
                        MessageBox.Show("Successfully done");
                    }
                }
                 catch (Exception ex)
                {
                        MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
                }
            }
           
else            {
                MessageBox.Show("Problem occured, try again later");
             }        }



cfile29.uf.1168363350AEC2F81E507C.zip

위 코드에서 알 수 있듯이 WPF 의 OpenFileDailog 역시 내부적으로는 Win32 API 를 사용한다.
OpenFileDialog 클래스의 사용 방법은 C++, WinForm 과 특별히 다르지 않다.



2010년 2월 18일 목요일

Timers in C#

Timers in C#



Timer 클래스를 사용하려다 보니 Timer 클래스가 여러군데 정의되어 있는것을 확인하였다. 조금은 집고 넘어가야 할 것 같다.


.NET Timer Class
.NET Windowns 프로그래밍에서는 다음과 같은 3가지의 Timer 클래스를 제공한다.
각각 스레드 타이머, 서버 기반 타이머, Windowns 기반 타이머 라고도 한다.

System.Threading.Timer         
System.Timers.Timer              
System.Windows.Forms.Timer  







.NET 웹 프로그래밍에서는 다음 Timer 클래스를 사용한다.

System.Web.UI.Timer




System.Windows.Forms.Timer
Windows 기반 타이머 이다.
Windows Form 응용프로그램에서 사용할 수 있도록 최적화 되어 있으며 창에서 사용해야 한다. 이 타이머 는 UI 스레드를 사용하여 프로세스를 수행하는 단일 스레드 환경용이다. 이 타이머는 UI 스레드가 프로세싱을 수행하는 데 사용하는 단일 스레드 환경을 위해 설계되었다. 이 타이머를 사용하려면 사용자 코드에 사용 가능한 UI 메시지 펌프가 있어야 하고 항상 같은 스레드에서 수행되거나 다른 스레드로의 호출을 마샬링해야 한다. 이 기능은 COM 구성 요소의 성능을 저하시킨다.
정확성이 높은 다중 스레드 타이머가 필요하면 System.Timers 네임스페이스의 Timer 클래스를 사용해야 한다.
cf) Timer 클래스 - MSDN



System.Threading.Timer

스레드 타이머 이다.
이벤트 대신 콜백 메서드를 사용하고 스레드 풀 스레드를 사용하는 단순한 경량 타이머 이다. UI 스레드에서 콜백이 발생하지 않기 때문에 Windows Form 에서는 사용하지 않는 것이 좋다. Windows  Form 에서는 System.Windows.Forms.Timer 클래스를 사용하는것이 더 좋다. 서버 기반 타이머 기능의 경우 이벤트를 발생시키고 추가 기능을 제공하는 System.Timers.Timer 를 사용할 수 있다. TimerCallback 델리게이트를 사용하여 Timer 에서 실행 할 메서드를 지정한다. 타이머 델리게이트는 타이머가 생성될 때 지정되며 변경할 수 없다. 해당 메서드는 타이머를 만든 스레드에서 실행되지 않으며 시스템에서 제공하는 ThreadPool 스레드에서 실행된다. 스레드 타이머는 메시지가 스레드에서 펌프되지 않는 경우에 유용하다. 예를 들어, Windows 기반 타이머는 운영 체제의 타이머 지원 기능에 의존하며 스레드에서 메시지를 펌프하지 않을 경우에는 타이머 관련 이벤트가 발생하지 않는다. 이 경우에는 스레드 타이머가 보다 유용하다.
cf) Timer 클래스 - MSDN



System.Timers.Timer
서버 기반 타이머 이다. 일반 타이머를 서버 환경에서 최적으로 실행되도록 업데이트한 것이다. 서버 기반 타이머를 사용하면 응용프로그램에서 발생되는 이벤트의 반복 간격을 지정할 수 있다. 그런 다음 이 이벤트를 처리하여 정기적인 프로세싱을 제공할 수 있다. 서버 기반 타이머는 다중 스레드 환경에서 작업자 스레드와 함께 사용하도록 설계되었다. 두 스레드는 서로 다른 아키텍처를 사용하므로 서버 기반 타이머가 Windows 타이머보다 정확하다. 서버 타이머는 스레드 사이를 이동하면서 발생한 이벤트를 처리할 수 있다. 즉, 멀티스레드 환경에선 서버 기반 타이머를 사용하자.
cf) 서버 기반 타이미 소개 - MSDN



Server-Based Timer Demo

서버 기반 타이머 예제를 살펴보자. 실은 아래 블로그 포스트를 보다가 생각이 나서 이 내용들을 정리하게 되었다.
참조) Timers in C# - www.c-sharpconer
다시 한번!! 서버 기반 타이머는 간격을 지정하여 이벤트를 발생 시키며 해당 이벤트 핸들러에 특정 처리를 넣어 주면 된다.

using System;

using System.Timers;

using System.Threading;



public class Test

{

    public static void Main()

    {

        System.Timers.Timer myTimer = new System.Timers.Timer();

        myTimer.Elapsed += new ElapsedEventHandler(OnTimer);

        myTimer.Interval = 1000;

        myTimer.Enabled = true;

        myTimer.AutoReset = false;



        Console.WriteLine(@"Press 'q' and 'Enter' to quit...");



        while (Console.Read() != 'q')

        {

            Thread.Sleep(1000);

        }

    }



    public static void OnTimer(Object source, ElapsedEventArgs e)

    {

        Console.WriteLine("DateTime: " + DateTime.Now);

        System.Timers.Timer theTimer = (System.Timers.Timer)source;

        theTimer.Interval += 1000;

        theTimer.Enabled = true;

    }

}



cfile24.uf.1424053850AEC2F71C3343.zip
코드와는 다르게 시간이 정확하지 않다. CPU 의 처리 우선순위 및 OS 의 멀티스레드 환경에 따라 이벤트 핸들러의 코드를 처리하기 때문에 정확하지는 않다.






2010년 2월 14일 일요일

Distinct Extension Method

원문 : Distinct Extension Method








Distinct Extension Method



배열에서 중복된 모든 요소를 제거하여 결과적으로 서로 다른 요소만 남게하는 가장 쉬운 방법은 무엇일까??  배열의 요소를 모두 순회하여 중복된 값을 제거해야 할까?? System.Linq 네임스페이스에는 Distinct 확장 메서드를 제공해 준다. Distinct 는 사전적인 의미로 "다른" 이라는 형용사 이다. 즉, 배열에서 서로 다른 요소만을 남겨 준다는 소리다. Distinct 는 배열에서 서로 다른 요소만을 정제(?)한 객체를 리턴해 준다.

여기서 집고 넘어가야 하는 것은 Distinct 는 확장 메서드라는것!!
System.Linq 네임스페이스를 using 해주지 않으면 Distinct 메소드를 인식하지 못한다.
아마도 System.Linq 네임스페이스 안에서 배열 클래스에 Distinct 확장 메서드를 추가해준 것 같다.


// Declare an array with some duplicated elements in it.
int[] array1 = { 1, 2, 2, 3, 4, 4 };

// Invoke Distinct extension method.
var result = array1.Distinct();

// Display results.
foreach (int value in result)
    Console.WriteLine(value);





Microsoft Chart Controls - Getting Started

Microsoft Chart Controls - Getting Started




■ Series and Points

Series and Chart Type
각각의 Series 는 ChartType 프로퍼티를 가지고 있다. ChartType 은 ChartArea 에 넣을 차트 타입을 결정한다. ChartType 에는 Pie, Line 등이 있다.




Series and Data Points
data series 는 data points 의 그룹과 관련되어 있다. data point 는 X, Y, 그리고 외형값 을 가지고 있다.
값의 구성은 chart type 에 따라 다르다. 즉, chart type 에 따라 여러개의 Y 값을 가질 수 있다. 예를 들어 Candlestick chart 는 high, low, open, close 값을 가진다.




Appearace Properties
다른 많은 차트 요소들과 같이 Series 는 아래와 같이 다양한 외관을 제공한다.
   - 다양한 스타일의 Gradient colors
   - 다양한 패턴을 가진 Hatching
   - 배경 이미지, 알파값 설정을 통한 투명 효과

Series 는 무제한의 data points 를 가질 수 있다. 또한 자신의 외관 프로퍼티(Gradient, Hatching Transparency)를 가질 수 있다. data point 의 외관 프로퍼티는 data point 소유 series 의 같은 프로퍼티보다 우선 시 된다.





■ 참조Microsoft Chart control for Windows Form







Microsoft Chart Controls

2010년 2월 12일 금요일

Convert integer to Byte Array in C#

원문 : Convert integer to Byte Array in C#







Convert integer to Byte Array in C#



BitConverter 클래스를 이용하면 기본 데이터 타입(base data type) 을 바이트 배열(array of byte) 로 또는 그 반대로 변변환할 수 있다.




BitConverter 클래스는 정적 클래스(static class) 이며, Object를 바로 상속한 클래스 이다.

 

public static class BitConverter
cf) BitConverter class - MSDN


BitConverter 클래스는 오버로드된 정적인 메소드 GetBytes 메소드를 가지고 있다. GetBytes 메소드는 integer, double 또는 base data type 을 byte 배열로 변환시켜준다. 반대로 byte 배열을 base data type 을 변환시켜주는 정적 메소드(ToDouble, ToBoolean, ToChart, ToInt16, ToSingle) 를 가지고 있다. 

다음의 코드 조각은 여러 int data 를 byte 배열로 변환하는 방법을 보여준다.

namespace BitConverterSample{    class Program    {        static void Main(string[] args)        {            Console.WriteLine("Int and byte arrays conversion sample.");
            // Create double to a byte array            Int32 i32 = 125;
            Console.WriteLine("Int value: " + i32.ToString());
            byte[] bytes = ConvertInt32ToByteArray(i32);

            Console.WriteLine("Byte array value:");            Console.WriteLine(BitConverter.ToString(bytes))
    
        Console.WriteLine("Byte array back to Int32:");

            // Create byte array to Int32            double dValue = ConvertByteArrayToInt32(bytes);
            Console.WriteLine(dValue.ToString());
            Console.ReadLine();       }


        public static byte[] ConvertInt32ToByteArray(Int32 I32)
        {            return BitConverter.GetBytes(I32);        }

        public static byte[] ConvertIntToByteArray(Int16 I16)        {            return BitConverter.GetBytes(I16);        }

        public static byte[] ConvertIntToByteArray(Int64 I64)        {            return BitConverter.GetBytes(I64);        }

        public static byte[] ConvertIntToByteArray(int I)        {            return BitConverter.GetBytes(I);        }

        public static double ConvertByteArrayToInt32(byte[] b)        {            return BitConverter.ToInt32(b, 0);        }    }}







cfile2.uf.1379C63750AEC2F30DC0E8.zip

2010년 2월 9일 화요일

Microsoft Chart Controls

Microsoft Chart Controls







간단히 차트가 필요했다. 많은 부분을 사용해야 하는 것이 아니라 Chart FX 를 구입해서 사용하기는 부담스러웠다. 무료로 사용할 수 있는 차트가 있나 살펴보다가 MS 에서 차트를 기본으로 제공해준다는 사실을 알았다. 사용 방법을 정리할 겸 작성해 본다.




■ 준비


1.
Microsoft .NET Framework 3.5용 Microsoft Chart Controls 다운로드 및 설치

   .NET Framework 3.5 SP1 용 ASP.NET 및 Windows Form 의 Chart Controls



2.
Microsoft .NET Framework 3.5용 Microsoft Chart Controls 언어 팩

   ASP.NET 및 Windows Form 의 Chart Controls 언어팩이다. 각 언어별로 오류 메시지와 같은 번역된 텍스트가 들어 있다. 필요에 따라 설치해 준다.



3.
Microsoft Chart Controls Add-on for Microsoft Visual Studio 2008   Chart 개발을 편리하게 하기 위하여 Visual Studio 2008 에 Add-on 시켜준다.


4.
Microsoft Chart Controls for .NET Framework Documentation

   MS Chart Controls 를 사용하기 위한 도움말 즉, MSDN 같은 도움말 문서이다.



5.
Samples Environment for Microsoft Chart Controls

   MS Chart Controls 의 사용 샘플이다.


Chart Controls 을 사용하기 위해서 다음 dll을 참조시켜야 한다.

System.Windows.Forms.DataVisualization.Charting

.NET Framework 3.5 에서는 위 차트 컨트롤을 설치 해야 하지만 .NET Framework 4.0 에서는 따로 설치하지 않아도 된다. 



■ 정보
Visual Studio 2008 Add-on

Visual Studio 2008 에 Add-on 시켰다면 도구 상자(ToolBox) 에 Chat 가 추가된 것을 확인할 수 있습니다.




Namespace


MS Chart Controls 사용을 위한 네임스페이스는 다음과 같습니다.


For ASP.NET         : System.Web.UI.DataVisualization.Charting


For Windows Form : System.Windows.Forms.DataVisualization.Charting



용어


MS Chart Contorls 에서 사용하는 용어 입니다.




Chart Picture

-  Chart Control 에 의해 렌더링된 표면의 전체 이미지를 말한다.


ChartArea- Chart 를 그리는 영역에 대한 부분으로 그래프를 그리는 밑바탕 (그래프의 X축, Y축, 모눈 등 해당) 이다.

- Chart Picture 는 하나 또는 여러개의 ChartArea 로 구성된다.


- ChartArea 는 직사각형의 영역으로 Series, Label, axes, tick mark 등이 그려지는 영역이다.


- 하나의 ChartArea 는 Chart Type 에 따라 여러개의 Series 를 가질 수 있다.


Series- 개별 그래프 및 데이터에 대한 부분 (그래프의 선, 원, 막대 등 해당)

- data point 들의 그룹과 관련되며, 각각의 series 는 chart type 과 연관되어 있다.




■ 참조


우선 MS Chart Control 을 사용하는데 MS 에서 제공하는 Document 를 보면 될 것 같다.


아래 웹 페이지도 참고 참고.


MS가 발표한 무료 Winform / ASP.NET 차트 - HOONS 닷넷
Microsoft Chat Control 사용하기 - TAEYO.NET
Microsoft Chart Controls - Getting Started








여담1.


Samples Environment for Microsoft Chart Controls 을 보면 차트를 쉽게 사용하기 위해선 Design Time 에 차트를 추가 하라고 말하고 있다. 차트를 사용하는 다른 개발자에게 물어보지 못해서 확인해 보지 못했지만 약 1 초 정도의 딜레이가 걸린다. 윈폼에 넣었을 때 Label 같은 리소스를 출력하는데 1초 동안 흰색 칸만 보여준다.



this.chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart();



과 같이 간단한 생성에서도 0.5 초 정도의 딜레이가 걸린다.

2010년 2월 8일 월요일

Get Icon From FileName in WPF

원문 : Get Icon From FileName in WPF








Get Icon From FileName in WPF



WPF 에서 파일 이름으로부터 아이콘을 얻어오는 방법이다. 우선 테스트할 WPF 데모 프로젝트를 만든다. 프로젝트 이름은 GetIconSample 이라고 했다.

테스트할 프로그램은 ListBox 를 갖는다. ListBox 에 파일을 추가하기 위하여 파일을 탐색하기 위한 Brows 버튼을 갖는다. ListBox 는 추가된 파일의 아이콘과 이름을 출력하게된다. 데모 프로그램의 외관은 아래와 같다.



우선 첫 번째로 파일 이름을 아이콘으로 변경하는 클래스를 작성한다. 이 클래스를 작성하기 위하여 System.Drawing 네임스페이스를 참조 추가 시키자.



클래스의 코드는 다음과 같다.
#region FileToImageIconConverter
    public class FileToImageIconConverter    {
        private string filePath;
        private System.Windows.Media.ImageSource icon;

        public string FilePath { get { return filePath; } }
        public System.Windows.Media.ImageSource Icon
        {
            get            {
                if (icon == null && System.IO.File.Exists(FilePath))
                {
                    using (System.Drawing.Icon sysicon = System.Drawing.Icon.ExtractAssociatedIcon(FilePath))
                    {
                        icon = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(
                                  sysicon.Handle,
                                  System.Windows.Int32Rect.Empty,
                                  System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                    }
                }

                return icon;
            }
        }

        public FileToImageIconConverter(string filePath)
        {
            this.filePath = filePath;
        }
    }
#endregion




xaml 코드는 다음과 같다.

<Window x:Class="GetIconSample.Window1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    Title="Window1" Height="337" Width="519">    <Window.Resources>        <ItemsPanelTemplate x:Key="ItemsPanelTemplate1">            <WrapPanel IsItemsHost="True"/>        </ItemsPanelTemplate>        <Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">            <Setter Property="Background" Value="Transparent"/>            <Setter Property="Padding" Value="2,0,0,0"/>            <Setter Property="Template">                <Setter.Value>                    <ControlTemplate TargetType="{x:Type ListBoxItem}">                        <Border HorizontalAlignment="Center" VerticalAlignment="Center">                            <StackPanel Orientation="Vertical">                                <Image x:Name="img" Source="{Binding FileIcon}" Height="32" Width="32"/>                                <TextBlock VerticalAlignment="Center" Width="75" TextWrapping="Wrap" Text="{Binding FileName}"/>                            </StackPanel>                        </Border>                    </ControlTemplate>                </Setter.Value>            </Setter>        </Style>    </Window.Resources>    <Grid>        <Button x:Name="btnBrowse" Click="btnBrowse_Click"                Content="Browse" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" VerticalAlignment="Top" Width="119"/>        <ListBox x:Name="lbFiles"
                 ItemContainerStyle="{DynamicResource ListBoxItemStyle}"                 ItemsPanel="{DynamicResource ItemsPanelTemplate1}"                 Margin="12,51,12,12" ScrollViewer.VerticalScrollBarVisibility="Visible" />
    </Grid>

</Window>



버튼 클릭 이벤트를 다음과 같이 구현해 주었다.

public partial class Window1 : Window    {
        ObservableCollection<MyFiles> myFilesList = new ObservableCollection<MyFiles>();

        public Window1()
        {
            InitializeComponent();
        }
        #region Button-Click-btnBrowse
        private void btnBrowse_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            ofd.Filter = "All files (*.*)|*.*";
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string filePath = ofd.FileName;
                FileToImageIconConverter some = new FileToImageIconConverter(filePath);
                ImageSource imgSource = some.Icon;
                myFilesList.Add(new MyFiles { FileName = ofd.SafeFileName, FileIcon = imgSource });
            }
            lbFiles.ItemsSource = myFilesList;
        }
        #endregion    }




2010년 2월 7일 일요일

Convert Enum

Convert Enum



enum 데이터 타입을 사용하면서 데이터 변환에 사용되는 몇가지 기술을 정리해 보았다.



Convert integer to Enum instance
enum 타입을 생성한 후에, enum 인스턴스의 값을 적절한 타입으로 변환해 주는 것은 어렵지 않다.
바로 Convert 클래스를 이용하면 쉽게 가능하다.
그런데... 보통 int 값을 해당 enum 인스턴스에 대입하려 할 때 쉽지 않음을 느꼈다.
처음에는 해당 int 값을 swich-case 문을 이용하여 값을 일일이 설정해 주었다. 코드만 길어지고 관리하기 효율적인 코드가 아니다.

Enum 클래스의 ToObject 정적 메소드를 이용하면 된다.
ToObject 정적 메소드는 지정된 값을 갖는 enum 인스턴스를 생성해 준다. object 타입으로 리턴하므로 적절히 타입 캐스팅을 해서 사용하면 된다. 예외처리 코드 다 빼고 핵심만을 코드로 작성한다면 다음과 같다.


public enum Day
{
        Mon = 0,
        Tue,
        Wed
}

public static void Main(string[] args)
{
    int a = 1;
    Day day = Day.Mon;

     day = (Day)Enum.ToObject(typeof(Day), a);

     Console.WriteLine("day = {0}", day.ToString());
     Console.ReadKey();
}






cfile22.uf.1267493750AEC2EC1B95EE.zip



Convert enum to string
enum 데이터의 상수값이 아닌 데이터 이름(?) 을 string 으로 변환하여 얻는 방법이다.
Enum.GetNames 정적 메소드를 이용하면 string[] 을 얻는다.
Enum.GetName 정적 메소드를 이용하면 지정한 값을 갖는 데이터 이름을 얻는다. 즉 string


Convert string to enum
Enum.Parse 정적 메소드를 이용한다. 지정한 string 이름의 값을 갖는 enum 인스턴스를 얻는다.


위 정적 메소드를 이용한 코드이다.






cfile29.uf.18714C4550AEC2ED167125.zip

2010년 2월 4일 목요일

Drag And Drop Item in ListBox in WPF

원문 : Drag And Drop Item in ListBox in WPF











Drag And Drop Item in ListBox in WPF




아래와 같이 두개의 ListBox 를 배치한다.



<Window x:Class="DragDropListBoxSample.Window1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    Title="Drag And Drop ListBox Item" Height="300" Width="529">    <Grid>        <ListBox x:Name="lbOne" PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown"                 HorizontalAlignment="Left" Margin="12,29,0,12" Width="215"
                 ScrollViewer.VerticalScrollBarVisibility="Visible" />
        <ListBox x:Name="lbTwo" Drop="ListBox_Drop" AllowDrop="True"                 HorizontalAlignment="Right" Margin="0,29,12,12" Width="215"
                 ScrollViewer.VerticalScrollBarVisibility="Visible"/>
        <TextBlock Height="21" Text="ListBox One" HorizontalAlignment="Left"
                   Margin="12,2,0,0" VerticalAlignment="Top" Width="120" />
        <TextBlock Height="21" Text="ListBox Two" HorizontalAlignment="Right"
                   Margin="0,2,107,0" VerticalAlignment="Top" Width="120" />
    </Grid></Window>

DragDrop 을 구현하기 위해 데이터를 Drag 할 ListBox 에서는 PreviewMouseLeftButtonDown 이벤트 핸들러를 정의해 주어야 한다. Drop 할 목적지 ListBox 에서는 AllowDrop 프로퍼티를 True 로 설정하고, Drop 이벤트 핸들러를 정의해주어야 한다.

PreviewMouseLeftButtonDown마우스 포인터가 ListBox 위에 있을 때 마우스 왼쪽 버튼을 클릭하면 발생하는 이벤트

AllowDrop
이 요소를 끌어서 놓기 작업의 대상으로 사용할 수 있는지 여부를 나타내는 값을 가져오거나 설정.
기본값은 false 이다.

Drop해당 요소에(ListBox) 아이템을 끌어다 놓았을 때 발생하는 이벤트


첫 번째 ListBox 에 테스트할 데이터를 넣는다. TimeZoneInfo 클래스로 부터 TimeZones 리스트를 넣어 준다.
public Window1()
{
    InitializeComponent();

    foreach (TimeZoneInfo tzi in TimeZoneInfo.GetSystemTimeZones())
    {
         zoneList.Add(tzi.ToString());
    }
    lbxOne.ItemsSource = zoneList;
}





PreviewMouseLeftButtonDown 이벤트 핸들러 구현 코드는 다음과 같다. GetDataFromListBox 메소드를 눈여겨 보자

ListBox
dragSource = null;
private void ListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    ListBox parent = (ListBox)sender;
    dragSource = parent;
    object data = GetDataFromListBox(dragSource, e.GetPosition(parent));

    if (data != null)
    {
        DragDrop.DoDragDrop(parent, data, DragDropEffects.Move);
    }
}#region GetDataFromListBox(ListBox,Point)
        private static object GetDataFromListBox(ListBox source, Point point)
        {
            UIElement element = source.InputHitTest(point) as UIElement;
            if (element != null)
            {
                object data = DependencyProperty.UnsetValue;
                while (data == DependencyProperty.UnsetValue)
                {
                    data = source.ItemContainerGenerator.ItemFromContainer(element);
                    if (data == DependencyProperty.UnsetValue)
                    {
                        element = VisualTreeHelper.GetParent(element) as UIElement;
                    }
                    if (element == source)
                    {
                        return null;
                    }
                }
                if (data != DependencyProperty.UnsetValue)
                {
                    return data;
                }
            }
            return null;
        }
       
#endregion






목적지 ListBox 의 Drop 이벤트 핸들러 구현 코드는 다음과 같다.

private void ListBox_Drop(object sender, DragEventArgs e)
{
     ListBox parent = (ListBox)sender;
     object data = e.Data.GetData(typeof(string));
     ((IList)dragSource.ItemsSource).Remove(data);
     parent.Items.Add(data);
 }



예제 소스
cfile7.uf.16510D3850AEC2EB28D589.zip