Window/WPF2011. 3. 4. 22:51
코드로 스토리보드를 작성하다보면

Storyboard.SetTargetProperty 를 사용하게 되는데요.

[ 함수 원형 ]
public static void SetTargetProperty(DependencyObject element, PropertyPath path)


정적 메소드로써
첫 번째 인자로  Timeline을 지정하고
두 번째 인자로 애니메이션을 적용할 종속성 속성 경로를 지정합니다.

보통 일반적인 프로퍼티를 설정하기 위해서는 다음과 같이 사용합니다.
Storyboard.SetTargetProperty(Timeline, new PropertyPath(FrameworkElement.OpacityProperty));


하지만,
RenderTransform 프로퍼티들을 설정하는 법은 약간 다릅니다.

1. 단일 속성일 경우

 RenderTransform = new ScaleTransform();

 
 
PropertyPath path = new PropertyPath("(0).(1)",

     new DependencyProperty[]
     { 
        
UIElement.RenderTransformProperty,
         ScaleTransform.ScaleXProperty

     });

 
Storyboard.SetTargetProperty(Timeline, path);


2. 다중 속성일 경우
 TransformGroup tg = new TransformGroup();

 tg.Children.Add(new ScaleTransform());

 tg.Children.Add(new RotateTransform());

 tg.Children.Add(new SkewTransform());

 tg.Children.Add(new TranslateTransform());

 

 RenderTransform = tg;

 PropertyPath path = new PropertyPath("(0).(1)[0].(2)",

     new DependencyProperty[]

     {

         UIElement.RenderTransformProperty,

         TransformGroup.ChildrenProperty,

         ScaleTransform.ScaleXProperty

     });

 Storyboard.SetTargetProperty(Timeline, path);


위의 두 소스는 비슷하지만 틀린점이 있다면
PropertyPath 함수의 첫 번째 인자로 들어가는 토큰화된 문자열과
TransformGroup.ChildrenProperty 가 추가된 점입니다.

 단일 속성일 경우엔 다음과 같이 지정이 되지만,

(0) : UIElement.RenderTransformProperty
(1) : ScaleTransform.ScaleXProperty

다중 속성일 경우엔 그룹 중 몇 번째 인지를 지정해야 주어야 합니다.
ScaleTransform 은 TransformGroup의 첫번째 자식임으로 [0] 을 지정하였습니다.

토큰화된 문자열만 잘 이해하신다면 쉽게 사용할 수 있습니다.

'Window > WPF' 카테고리의 다른 글

WPF Media Player ( Design. GomPlayer )  (0) 2012.03.12
Brush ColorAnimation  (0) 2011.06.22
ListBox ItemsPanel 변경하기  (0) 2011.03.04
Image Rotate  (4) 2010.11.04
[ WPF ] Custom Slider  (4) 2010.08.13
Posted by 열ㅇl
Window/WPF2011. 3. 4. 21:19

ItemsPanel 을 변경하는 두 가지 방법에 대해 알아보겠습니다.

다음 코드들은
Grid 패널의 정렬 속성을 설정하고 ItemsPanel 로 설정하는 동일한 코드입니다.

1. Xaml 코드 사용

 StringBuilder xaml = new StringBuilder();
 
xaml.Append("<ItemsPanelTemplate xmlns=\"");
 xaml.Append("http://schemas.microsoft.com/winfx/2006/xaml/presentation\">");
 xaml.Append("<Grid HorizontalAlignment=\"Left\" VerticalAlignment=\"Top\" />");
 xaml.Append("</ItemsPanelTemplate>");
 StringReader stringReader = new StringReader(xaml.ToString());
 XmlReader xamlReader = XmlReader.Create(stringReader);
 
ItemsPanel = (ItemsPanelTemplate)XamlReader.Load(xamlReader);


2.
FrameworkElementFactory 클래스 사용

 FrameworkElementFactory factory = new FrameworkElementFactory(typeof(Grid));
 
factory.SetValue(Grid.HorizontalAlignmentProperty, HorizontalAlignment.Left);
 
factory.SetValue(Grid.VerticalAlignmentProperty, VerticalAlignment.Top);
 
ItemsPanel = new ItemsPanelTemplate(factory);


'Window > WPF' 카테고리의 다른 글

Brush ColorAnimation  (0) 2011.06.22
Storyboard.SetTargetProperty에 RenderTransformProperty 설정하기  (0) 2011.03.04
Image Rotate  (4) 2010.11.04
[ WPF ] Custom Slider  (4) 2010.08.13
[ WPF ] ClickOnce로 배포하기  (9) 2010.08.03
Posted by 열ㅇl
Window/WPF2010. 11. 4. 16:11

이미지를 마우스로 회전 하는 예제입니다.

 

 

소스는 다음과 같습니다.

 

public partial class Window1 : Window

    {

        private RotateTransform rotateTransform;

        private double angle;

        private double rotate;

        private Vector position;

 

        public Window1()

        {

            InitializeComponent();

            Loaded += new RoutedEventHandler(Window1_Loaded);

        }

 

        private void Window1_Loaded(object sender, RoutedEventArgs e)

        {

            vinyl.MouseLeftButtonDown += new MouseButtonEventHandler(vinyl_MouseLeftButtonDown);

            vinyl.MouseMove += new MouseEventHandler(vinyl_MouseMove);

            vinyl.MouseLeftButtonUp += new MouseButtonEventHandler(vinyl_MouseLeftButtonUp);

 

            rotateTransform = new RotateTransform();

            vinyl.RenderTransform = rotateTransform;

            vinyl.RenderTransformOrigin = new Point(0.5, 0.5);

 

            position = VisualTreeHelper.GetOffset(vinyl);

            position.X += vinyl.Width / 2;

            position.Y += vinyl.Height / 2;   

        }

 

        private void vinyl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            Mouse.Capture(vinyl, CaptureMode.None);

        }

 

        private void vinyl_MouseMove(object sender, MouseEventArgs e)

        {

            if (e.LeftButton == MouseButtonState.Pressed)

            {

                Point currentPoint = e.GetPosition(this);

 

                double _angle = Math.Atan2(position.Y - currentPoint.Y, position.X - currentPoint.X) *

(180 / Math.PI);

                rotateTransform.Angle = rotate + _angle - angle;

            }

        }

 

        private void vinyl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Mouse.Capture(vinyl, CaptureMode.Element);

            Point point = e.GetPosition(this);

           

            angle = Math.Atan2(position.Y - point.Y, position.X - point.X) * (180 / Math.PI);

            rotate = rotateTransform.Angle;

        }

    }


Posted by 열ㅇl
Window/WPF2010. 8. 13. 23:22

 

이번 포스팅은 Slider에 대한 내용입니다.

우리가 사용하고 있는 미디어 플레이어 같은 프로그램들은 아래와 같이 슬라이더 바의 어느 영역을

클릭하고 움직이더라도 해당 지점으로 슬라이더의 위치가 움직입니다.

 

 

하지만 Slider컨트롤을 사용해보면 Thumb 영역이 아닌 다음과 같은 빨간 영역을 클릭 하게 되면 해당 위치로

Thumb 이 움직이나 이 후에 마우스 왼쪽 버튼을 클릭한 상태에서 움직여 보아도 Thumb 은 따라 오질 않습니다.

 

 

이를 개선하기 위한 방법으로

SliderPreviewMouseMove 이벤트를 사용하여 Slider내의 마우스 좌표 값을 SliderValue 값으로 변경 하였습니다.

 

코드는 다음과 같습니다.

Slider를 상속받은 CustomSlider 클래스를 생성하였고 AutoMoveProperty 라는 프로퍼티를 만들어

프로퍼티 값 변경에 따라 작성한 PreviewMouseMove 이벤트를 연결 / 제거 합니다.

     class CustomSlider : Slider

    {

        // 이전 IsMoveToPointEnabled 값으로 되돌리기 위한 플래그

        private bool defaultIsMoveToPointEnabled;

 

        public static readonly DependencyProperty AutoMoveProperty =

            DependencyProperty.Register(

           "AutoMove",

           typeof(bool),

           typeof(CustomSlider),

           new FrameworkPropertyMetadata(false, ChangeAutoMoveProperty));

 

        public bool AutoMove

        {

            get { return (bool)GetValue(AutoMoveProperty); }

            set { SetValue(AutoMoveProperty, value); }

        }

 

        private static void ChangeAutoMoveProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            CustomSlider slider = d as CustomSlider;

 

            if (slider != null)

            {

                if ((bool)e.NewValue)

                {

                    slider.defaultIsMoveToPointEnabled = slider.IsMoveToPointEnabled;

                    slider.IsMoveToPointEnabled = true;

                    slider.PreviewMouseMove += CustomSlider_PreviewMouseMove;

                }

                else

                {

                    slider.IsMoveToPointEnabled = slider.defaultIsMoveToPointEnabled;

                    slider.PreviewMouseMove -= CustomSlider_PreviewMouseMove;

                }

            }

        }

 

        private static void CustomSlider_PreviewMouseMove(object sender, MouseEventArgs e)

        {

            if (e.LeftButton == MouseButtonState.Pressed)

            {

                CustomSlider slider = sender as CustomSlider;

 

                Point point = e.GetPosition(slider);

 

                // 현재 Slider 내 마우스 좌표 값을 Value 값으로 계산.

                slider.Value = point.X / (slider.ActualWidth / slider.Maximum);

            }

        }

    }

 

이를 Sliverlight에서 적용해보니 역시나 프로퍼티 오류등을 보이며 제대로 되지 않더군요. -_-

그래서 Sliverlight 환경에 맞게 다시 수정해 보았습니다.

 

크게 바뀐 점은 없고 Sliverlight 에서 없는 IsMoveToPointEnabled 프로퍼티를 삭제하고

WPF 와 달리 마우스 이벤트로 넘어온 인자를 통해 MouseButton의 상태를 알 수 없기 때문에 이를 확인하기 위해

마우스의 다운과 업 이벤트에서 플래그 값을 변경하였습니다.

또한 Slider의 마우스 다운과 업 이벤트를 발생시키 위해서 새로 핸들러를 추가하였습니다.

  public partial class CustomSlider : Slider

    {

        private bool IsMouseLeftDown;

 

        public static readonly DependencyProperty AutoMoveProperty =

            DependencyProperty.Register(

           "AutoMove",

           typeof(bool),

           typeof(CustomSlider),

           new PropertyMetadata(false, ChangeAutoMoveProperty));

 

        public bool AutoMove

        {

            get { return (bool)GetValue(AutoMoveProperty); }

            set { SetValue(AutoMoveProperty, value); }

        }

 

        public CustomSlider()

        {

            AddHandler(FrameworkElement.MouseLeftButtonDownEvent,

                new MouseButtonEventHandler(MouseLeftDown), true);

            AddHandler(FrameworkElement.MouseLeftButtonUpEvent,

                new MouseButtonEventHandler(MouseLeftUp), true);

        }

 

        private void MouseLeftDown(object sender, MouseButtonEventArgs e)

        {

            Point point = e.GetPosition(this);

            Value = point.X / (ActualWidth / Maximum);

            IsMouseLeftDown = true;

        }

 

        private void MouseLeftUp(object sender, MouseButtonEventArgs e)

        {

            IsMouseLeftDown = false;

        }

 

        private static void ChangeAutoMoveProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            CustomSlider slider = d as CustomSlider;

 

            if (slider != null)

            {

                if ((bool)e.NewValue)

                {

                    slider.MouseMove += CustomSlider_PreviewMouseMove;

                }

                else

                {

                    slider.MouseMove -= CustomSlider_PreviewMouseMove;

                }

            }

        }

 

        private static void CustomSlider_PreviewMouseMove(object sender, MouseEventArgs e)

        {

            CustomSlider slider = sender as CustomSlider;

           

            if (slider.IsMouseLeftDown)

            {

                Point point = e.GetPosition(slider);

 

                slider.Value = point.X / (slider.ActualWidth / slider.Maximum);

            }

        }

    }

 

- XAML 에서의 사용법은 다음과 같이 AutoMove 멤버의 값을 True로 설정함으로써 사용할 수 있습니다.

 

<local:CustomSlider VerticalAlignment="Center" AutoMove="True"/>


- 블랜드에서는 다음과 같이 AutoMove 를 체크하여 사용하 실 수 있습니다.

 

소스를 받아 테스트 해보시면 잘 따라 움직이는 것을 보실 수 있습니다.

'Window > WPF' 카테고리의 다른 글

ListBox ItemsPanel 변경하기  (0) 2011.03.04
Image Rotate  (4) 2010.11.04
[ WPF ] ClickOnce로 배포하기  (9) 2010.08.03
[ WPF ] RegisterWindowMessage 를 이용한 프로그램 간 메시지 보내기  (178) 2010.07.21
[ WPF ] BackgroundWorker  (2) 2010.07.11
Posted by 열ㅇl
Window/WPF2010. 8. 3. 18:58

많은 배포 프로그램 중에서 가장 손쉽게 배포할 수 있는 것이 닷넷 2.0에서 발표된 ClickOnce가 아닌가 싶습니다.

게시한 URL만 알고 있으면 손쉽게 한번의 클릭으로 모든 걸 쉽게 할 수 있으니까요.^^

개발자의 측면에서는 더할 나위없이 편한 방법이 아닐 수 없습니다. ( 자동 업데이트 기능 등.. )

 

이번 포스팅에서는 WPF 프로그램을 ClickOnce로 배포하는 방법에 대해 알아보겠습니다.

3가지의 형태로 배포를 할 수 있는데요.

배포 방식 : http://msdn.microsoft.com/ko-kr/library/71baz9ah(VS.90).aspx

그 중 웹 배포에 대해 진행하겠습니다.

 

우선 컴퓨터에 IIS를 설치해야 할텐데요.

윈도우 7을 기준으로 알아보겠습니다. ( IIS 7.0 )

 

먼저,

[제어판] -> [프로그램 및 기능] -> [ Windows 기능 사용 / 사용 안함 ] 을 클릭합니다.

 

여러가지 Windows 기능 중에서 [ 인터넷 정보서비스 ] 탭을 체크 하면 기본 설정 값들에 체크가 되어집니다.

이 후 이 탭을 확장하여 배포에 필요한 다음 요소들을 체크 후 확인을 누릅니다.

 

- IIS 6 메타베이스 및 IIS 6 구성 호환성

- ASP.NET

- Windows 인증

 

설정이 완료 된후 웹 페이지 주소창에 http://localhost/ 를 입력하여 다음 그림이 나타나면 설치 완료!!

 

자, 그럼 이제 본격적으로 ClickOnce 배포를 해보겠습니다.

로컬 IIS 웹 사이트에 엑세스 하려면 관리자 계정의 컨텍스트에서 Visual Studio 를 실행해야 하기 때문에

Visual Studio를 마우스 오른쪽으로 클릭하여 관리자 권한으로 실행하여야 합니다.

 

 

간단하게 다음과 같은 프로그램을 만들었습니다.

 

이 후 프로젝트의 속성을 클릭합니다.

 

여러가지 속성 중에 서명, 보안, 게시 탭을 설정해 주어야 하는데요.

 

서명 탭을 클릭하여 간단하게 서명을 해보겠습니다.

테스트 프로그램이기 때문에 테스트 인증서 만들기를 클릭하여 암호를 입력하세요.

자세한 내용은 다음 주소를 참고하세요.

http://msdn.microsoft.com/ko-kr/library/che5h906(v=VS.80).aspx

 

보안 탭을 보시면 다음과 같이 완전 신뢰와 부분 신뢰를 선택할 수 있는데요.

다음 주소를 참고하여 프로그램 특성에 맞게 설정해주시면 되겠습니다.

http://msdn.microsoft.com/ko-kr/library/z17ceyya(VS.90).aspx

 

마지막으로 게시 탭입니다.

폴더 위치 게시는 현재 배포되는 위치 이며 설치 폴더 URL은 ClickOnce Application 이 실행되는 곳입니다.

배포 위치와 같다면 설정하지 않으셔도 됩니다.

 

설치 모드 및 설정

온라인으로만 응용 프로그램 사용 가능일 경우 배포된 웹 사이트에서만 실행이 가능하며,

오프라인으로도 응용 프로그램 사용 가능일 경우 로컬의 시작메뉴에서 실행이 가능합니다.

 

응용프로그램 파일은 실제 배포되는 파일들을 선택/설정할 수 있습니다.

필수구성요소는 프로그램 실행에 필요한 필수 구성요소에 대해 선택하고 설정 할 수 있습니다.

업데이트는 프로그램에 대한 업데이트 여부와 업데이트 시기등을 설정할 수 있습니다.

옵션은 설명( 게시 언어, 게시자 이름 등 ), 배포, 매니페스트, 파일연결에 대한 설정을 할 수 있습니다.

메니페스트의 바탕화면 바로 가기 만들기를 클릭하여 바로가기를 만들 수 있습니다.

 

게시 버전은 배포할 버전을 설정합니다.

게시 마법사는 위의 기능들 중 몇 가지만을 설정하여 게시할 수 있습니다.

 

배포 위치를 현재 로컬 주소의 ClickOnceTest 라는 가상 디렉토리로 설정하고

업데이트 시기를 응용프로그램 시작 전으로 설정합니다.

 

자, 그럼 지금 게시를 눌러 배포를 실행하겠습니다.

성공적으로 게시가 되었다면 해당 폴더와 파일들을 C:\inetpub\wwwroot 경로에서 확인 할 수 있습니다.

 

그럼 이제 설정한 해당 주소로 접속하여 파일을 실행하겠습니다.

http://localhost/ClickOnceTest/setup.exe

 

다음과 같이 파일 다운로드 창이 뜬 후 실행을 누르면

 

아래와 같은 창이 뜬 후 실행이 되어집니다.

  

  

 

시작 메뉴에 프로그램이 등록되어 지며 프로그램 및 기능에서 삭제할 수 있습니다.

 

프로그램을 수정하여 다시 게시한 후 프로그램을 실행하게 되면 업데이트 설치 여부를 물어보며

OK를 누르면 새로 수정된 프로그램이 실행되어 지는 것을 확인 할 수 있습니다.

       

  

 

ClickOnce의 Update 는 수정된 어셈블리만 다운받아 수정하므로 굉장히 효율적입니다.

ClickOnce에 대한 자세한 내용은 다음 URL을 참고하세요.

http://msdn.microsoft.com/ko-kr/library/t71a733d(VS.80).aspx

'Window > WPF' 카테고리의 다른 글

Image Rotate  (4) 2010.11.04
[ WPF ] Custom Slider  (4) 2010.08.13
[ WPF ] RegisterWindowMessage 를 이용한 프로그램 간 메시지 보내기  (178) 2010.07.21
[ WPF ] BackgroundWorker  (2) 2010.07.11
[ WPF ] 윈도우 이벤트  (4) 2010.07.11
Posted by 열ㅇl
Window/WPF2010. 7. 21. 21:22

서로 다른 응용 프로그램 사이에 메시지를 전달하는 방법에 대해 알아보겠습니다.

API 함수인 RegisterWindowMessage PostMessage 를 활용하면 되는데요.

 

RegisterWindowMessage 메시지를 등록하여 사용하기 때문에 서로 다른 프로그램에서 메시지를 약속하여야 합니다.

 

다음과 같은 원형을 가지고 있고 송수신 하는 프로그램에서 모두 실행하여야 합니다.

 uint RegisterWindowMessage (string lpString);

 

이 후에 PostMessage 함수를 사용하여 메시지를 보내주면 됩니다.

 bool PostMessage (IntPtr hWnd, uint Msg, uint wParam, uint lParam);

 

PostMessage 의 첫 번째 인자로 HWND_BROADCAST(0xffff) 값을 넣어주어야

다른 프로그램으로 메시지를 전송할 수 있습니다.

 

두 번째 인자로는 RegisterWindowMessage 함수를 실행한 반환 값을 넣어 주면 됩니다.

 

세 번째와 네 번째 인자를 사용하여 추가적으로 정보를 보낼 수 있습니다. (wParam : 2Byte, lParam : 4Byte)

이 방법은 4Byte 이상의 정보를 보낼 수 없다는 단점이 있습니다.

 

이 두 함수를 통해서 다른 프로그램으로 메시지를 보낼 수 있게 되었습니다.

 

그럼, 이제 메시지를 수신하는 방법을 알아보겠습니다.

윈도우 메시지를 수신해야 하는데요.

지난 번 포스팅 방법을 사용하겠습니다. ( http://shine10ee.blog.me/10089908443 )

 

다음과 같이 조건문을 거친 후 사용하시면 되겠습니다.

 void ComponentDispatcher_ThreadFilterMessage(ref MSG msg, ref bool handled)

{

    if (msg.message == 메시지 반환 값 && msg.wParam != 윈도우 핸들)

    {

       // To do ( msg.lParam 값으로 정보 확인 )

    }

}

 

이로써 WPF 에서 약속한 메시지를 수신할 수 있게 되었습니다.

 

간단한 예제로써 MFC 와 WPF 사이에 메시지를 송 수신하는 프로그램을 만들어 보았습니다.

MFC 프로그램의 코드에서도 위와 마찬가지 과정을 포함하고 있습니다.

 

소스는 다음과 같습니다.

 

[ WPF ]

 public partial class Window1 : Window

{

    private uint message;

    private IntPtr handle;

 

    public const uint HWND_BROADCAST = 0xffff;

 

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]

    public static extern uint RegisterWindowMessage(string lpString);

 

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]

    public static extern bool PostMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

 

    public Window1()

    {

        InitializeComponent();

    }

 

    protected override void OnSourceInitialized(EventArgs e)

    {

        base.OnSourceInitialized(e);

 

        handle = new WindowInteropHelper(this).Handle;

        message = RegisterWindowMessage("User Message");

        ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcher_ThreadFilterMessage);

    }

 

    void ComponentDispatcher_ThreadFilterMessage(ref MSG msg, ref bool handled)

    {

        if (msg.message == message && msg.wParam != handle)

        {

            MessageBox.Show("MFC Message : " + msg.lParam.ToString());

        }

    }

 

    private void Button_Click(object sender, RoutedEventArgs e)

    {

        PostMessage((IntPtr)HWND_BROADCAST, message, (uint)handle, 100);

    }

}


 

[ MFC ]

BOOL CRegisterWindowMessage_MFCDlg::OnInitDialog()

{

    CDialog::OnInitDialog();

 

    // 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는

    //  프레임워크가 이 작업을 자동으로 수행합니다.

    SetIcon(m_hIcon, TRUE);            // 큰 아이콘을 설정합니다.

    SetIcon(m_hIcon, FALSE);        // 작은 아이콘을 설정합니다.

 

    // 메시지 등록

    message = RegisterWindowMessage(_T("User Message"));

 

    return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.

}

 

void CRegisterWindowMessage_MFCDlg::OnBnClickedButton1()

{

    // 메시지 보내기

    ::PostMessage(HWND_BROADCAST, message, (WPARAM)this->GetSafeHwnd(), 200);

}

 

LRESULT CRegisterWindowMessage_MFCDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

{

    // 메시지 수신

    if(message == this->message && (HWND)wParam !=this->GetSafeHwnd())

    {

        char buf[256];

 

        sprintf_s(buf, "WPF Message : %d", lParam);

        MessageBox(buf);

    }

 

    return CDialog::WindowProc(message, wParam, lParam);

}

 

[ 실행 화면 ]

               [ WPF ]                                                       [ MFC ]

 

 

                                              [ MFC -> WPF ]

 

 

                                             [ WPF -> MFC ]

 

'Window > WPF' 카테고리의 다른 글

[ WPF ] Custom Slider  (4) 2010.08.13
[ WPF ] ClickOnce로 배포하기  (9) 2010.08.03
[ WPF ] BackgroundWorker  (2) 2010.07.11
[ WPF ] 윈도우 이벤트  (4) 2010.07.11
[ WPF ] OpenCV로 캠 화면 띄우기  (3) 2010.06.20
Posted by 열ㅇl
Window/Surface2010. 7. 15. 10:38

Surface SDK 는 기본적으로 태그 인식 기능이 내장되어 있어 이를 인식할 수 있습니다.

 

제공되는 태그는 Byte TagIdentity Tag 2가지 종류가 있습니다.

Byte Tag는 1byte의 data 값으로 256가지의 종류가 있고 Identity Tag는 16byte의 data값으로 종류가 제한되어 있지 않습니다.

또한 제공되는 태그 외에 사용자가 직접 만들어 낼 수 도 있습니다.

 

태그에 대한 자세한 내용은 다음 주소를 참고 하시면 됩니다.

ms-help://MS.VSCC.v90/MS.VSIPCC.v90/Microsoft.Surface/Microsoft.Surface.SDK/Development/TaggedObjects/

TaggedObjects.htm

 

TagVisualization 의 아키텍쳐와 인식 절차는 그림과 같습니다.

 

[ Architecture ]

 

[ Process ]

 

그럼 Tag를 인식하는 간단한 예제를 작성해 보겠습니다.

 

- Surface 프로젝트를 생성한 후 새 항목을 추가합니다.

 

- 다음과 같이 TagVisualization을 추가합니다.

 

- Surface Window XAML에 다음과 같은 코드를 작성합니다.

 

 

보시면 Grid 안에 TagVisualizer를 추가한 후 DefinitionsByteTag를 인식할 수 있도록 추가하였습니다.

Value는 태그의 번호이며 TagRemovedBehavior는 태그의 인식이 사라질 때 어떤 식으로 사라지게 할 것인지에 대한 플래그 값입니다.

FadeOpacity값이 서서히 줄면서 사라지는 애니메이션입니다.

LostTagTimeout은 해당 태그와 연결된 Source가 사라지는 시간이고 Source는 태그가 인식 되었을 때 나타날 TagVisualization 입니다.

 

위에 추가한 TagVisualization 은 ScatterView를 Content로 검은색의 Ellipse를 바탕으로 가지고 있으며 이미지들을 자식들로

추가하는 코드가 작성되어 있습니다.

 

태그가 인식이 되어지면 Source로 연결된 객체가 새로 생성이 됩니다.

이 때 윈도우에서는 아키텍쳐와 같은 이벤트들이 발생하게 됩니다.

 

[ 결과 화면 ]

검은색 원 부분이 ImageTagVisualization 영역입니다.

테스트 해보시면 알겠지만 ImageTagVisualization에 추가된 이미지들은 해당 영역에서만 움직일 수 있고 윈도우 영역으로는

이동이 되어지지 않는데요. 서로 다른 영역이기 때문에 당연한 결과겠죠.

 

다음 포스팅에서는 DragandDrop 기능을 사용하여 윈도우 영역으로 이미지를 이동하는 방법에 대해 포스팅하겠습니다.

 

TagVisualization에 대한 자세한 내용은 다음 주소를 참고하세요.

ms-help://MS.VSCC.v90/MS.VSIPCC.v90/Microsoft.Surface/Microsoft.Surface.SDK/ProgrammersGuide/TagVisualization/

TagVisualization.htm

Posted by 열ㅇl
Window/WPF2010. 7. 11. 15:46

어떤 작업이 오래 걸리는 경우 사용자에게 현재 진행률을 보여줘야 하는 경우가 있습니다.

이 경우에 사용할 수 있는 쓰레드가 BackgroundWorker 입니다.

백그라운드에서 비동기적으로 실행이 되는 동안 호출 스레드는 계속 정상적으로 실행이 됩니다.
 
현재 진행률을 설정할 수 있으며 작업이 완료된 시점의 이벤트를 발생할 수 있습니다.
중간에 작업을 취소할 수도 있습니다.

예제로 간단하게 버튼을 누르면 0에서 100까지의 진행률을 보여주며 중간에 Cancle 버튼을 누르면 작업이
취소되도록 하였습니다. UI 작업을 보여주기 위해 작업 동안 Ellipse를 랜덤하게 뿌려주게 하였습니다.
 
소스는 다음과 같습니다.

 public partial class Window1 : Window

{

    private BackgroundWorker thread = new BackgroundWorker();

    private readonly int max = 100;

    private BrushConverter brushConverter = new BrushConverter();

    private Random random = new Random();

 

    public Window1()

    {

        InitializeComponent();

    }

 

    protected override void OnInitialized(System.EventArgs e)

    {

        base.OnInitialized(e);

 

        progress.Maximum = max;

 

        // 진행률 전송 여부

        thread.WorkerReportsProgress = true;

 

        // 작업 취소 여부

        thread.WorkerSupportsCancellation = true;

 

        // 작업 쓰레드

        thread.DoWork += new DoWorkEventHandler(thread_DoWork);

 

        // 진행률 변경

        thread.ProgressChanged += new ProgressChangedEventHandler(thread_ProgressChanged);

 

        // 작업 완료

        thread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(thread_RunWorkerCompleted);

    }

 

    void thread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

    {

        btnStart.Content = "Start";

        string result = "작업이 완료되었습니다.";

 

        // 작업이 취소된 경우

        if (e.Cancelled)

        {

            result = "작업이 취소되었습니다.";

        }

 

        MessageBox.Show(result);

    }

 

    void thread_ProgressChanged(object sender, ProgressChangedEventArgs e)

    {

        int value = e.ProgressPercentage;

 

        // 변경 값으로 갱신

        progress.Value =value;

        progressValue.Text = value.ToString() + "%";

    }

 

    void thread_DoWork(object sender, DoWorkEventArgs e)

    {

        BackgroundWorker worker = sender as BackgroundWorker;

 

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

        {

            // CancelAsync() 메서드가 호출되었다면 정지

            if (worker.CancellationPending == true)

            {

                e.Cancel = true;

                break;

            }

            else

            {

                System.Threading.Thread.Sleep(50);

 

                // UI 쓰레드에 접근

                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()

                {

                    ellipseGrid.Children.Add(RandomEllipse());

                });

 

 

                // 진행률 변경 값 전송

                worker.ReportProgress(i);

            }

        }

    }

 

[ 작업 진행 화면 ]

 

[ 작업 완료 화면 ]

 

[ 작업 취소 화면 ]

Posted by 열ㅇl
Window/WPF2010. 7. 11. 15:26

윈도우 이벤트를 가로채기 위해서 HwndSource.AddHook 방법을 많이 사용하지만 이 방법은

조금 느린 반응과 HwndSource.FromHwnd 로 얻어낸 HWND 윈도우에서 발생하는 메시지만 수신된다는 단점이 있는데요.
 
이 단점이 없는 방법으로 ComponentDispatcher.ThreadMessage 가 있습니다.

사용법은 다음과 같습니다.
 

  private void Window_Loaded(object sender, RoutedEventArgs e)

 {

    ComponentDispatcher.ThreadFilterMessage +=

       new ThreadMessageEventHandler(ComponentDispatcher_ThreadFilterMessage);

 }



void ComponentDispatcher_ThreadFilterMessage(ref MSG msg, ref bool handled)

{

   switch (msg.message)

   {

        // To do

   }

}

 
Win32의 메시지와 동일한 값으로 필요한 메시지들을 다음과 같이 정의하여 비교하시면 됩니다.
 

uint WM_CREATE = 0x0001;

uint WM_DESTROY = 0x0002;

uint WM_MOVE = 0x0003;

uint WM_SIZE = 0x0005;

 

참고로 윈도우의 핸들은 다음과 같이 얻어 올 수 있습니다.

IntPtr hwnd = new WindowInteropHelper(this).Handle;

Posted by 열ㅇl
Window/Surface2010. 7. 10. 20:56

지난번 포스팅에 이어 LibraryStrack LibraryBar 컨트롤의 Drop 기능 구현에 대해 알아보겠습니다.

 

기본적으로 Drag and Drop 기능을 포함하고 있는 컨트롤 들이지만 다른 영역에서 컨트롤 안으로의 객체 삽입은

 

되지만 컨트롤 안에서 밖으로의 객체 삽입은 되지 않는데요. 이를 위해 구현되어 할 이벤트들이 있습니다.

 

ScatterViewSurfaceDragDrop.Drop 이벤트와 ScatterViewItem.ScatterManipulationStarted 이벤트 입니다.

 

또한 ScatterView의 속성 중 변경 할 값들이 있습니다. Drop이벤트를 발생시키기 위해 AllowDrop 값을 True

 

Background의 값을 지정해주어야 합니다. ( 투명하게 하기 위해 Transparent 값을 지정하였습니다. )

 

간단하게 소스를 통해 알아 보겠습니다.

 

        // Drop 이벤트

        private void ScatterView_Drop(object sender, SurfaceDragDropEventArgs e)

        {

            // 현재 커서로 만들어져 들어온 객체

            // 다른 영역으로의 Drag를 위하여 Surface에서는 BeginDragDrop 이벤트 발생 시

            // 커서를 선택된 객체로 변경하여 움직입니다.

            SurfaceDragCursor droppingCursor = e.Cursor;

 

            // 현재 Drop 된 영역이 SactterView 이고 Drag가 시작된 영역이 ScatterView 아니면

            if (droppingCursor.CurrentTarget == scatterView && droppingCursor.DragSource != scatterView)

            {

                // ScatterView의 아이템이 아니면

                if (!scatterView.Items.Contains(droppingCursor.Data))

                {

                    // 아이템을 추가 시킵니다.

                    scatterView.Items.Add(droppingCursor.Data);

 

                    // 커서로 넘어온 데이터를 ScatterViewItem으로 변경합니다.

                    var svi = scatterView.ItemContainerGenerator.ContainerFromItem(droppingCursor.Data)

                                      as ScatterViewItem;

 

                    if (svi != null)

                    {

                        // Center 및 Orientation등의 값들을 현재 커서 값으로 변경합니다.

                        svi.Center = droppingCursor.GetPosition(this);

                        svi.Orientation = droppingCursor.GetOrientation(this);

                        svi.Height = droppingCursor.Visual.ActualHeight;

                        svi.Width = droppingCursor.Visual.ActualWidth;

                        svi.SetRelativeZIndex(RelativeScatterViewZIndex.Topmost);

                    }

                }

            }

        }

 

        // ScatterView의 아이템이 선택되어질 때 발생

        private void ScatterView_ScatterManipulationStarted(object sender, 

                                                                                         ScatterManipulationStartedEventArgs e)

        {

            ScatterViewItem svi = e.OriginalSource as ScatterViewItem;

 

            // ScatterViewItem 아이템일 때만

            if (svi != null)

            {

                // Drag을 시작합니다.

                svi.BeginDragDrop(svi.DataContext);

            }

        }

 

[ 실행화면 ]

 

- ScatterView안의 Image 객체들

 

- LibraryBar 컨트롤 안에 옮겨진 객체 중 빨간 테두리의 객체를 선택하여 밖으로 꺼내었습니다.

 

- 현 위치에 삽입되어졌습니다.

 

특별히 어려운 내용은 없지만 Surface에서는 BeginDragDrop 이벤트 발생시 커서를 선택된 객체로 변경하게 되고

Drop 이벤트 발생 시 해당 객체의 정보들이 인자로 넘어온 다는 점을 아시면 되겠습니다.

 

다음 포스팅에서는 Tag를 인식하는 법에 대해 알아보겠습니다.

'Window > Surface' 카테고리의 다른 글

[ Surface 2.0 ] SurfaceScrollViewer Transform Behavior  (1) 2012.09.18
[ WPF ] TagVisualization  (0) 2010.07.15
[ WPF ] Surface LibraryStack & LibraryBar  (0) 2010.07.04
[ WPF ] Surface ScatterView  (0) 2010.07.03
[ WPF ] Surface SDK 예제  (0) 2010.07.03
Posted by 열ㅇl