모니터 해상도(Tip)

WPF에서 모니터의 실제 해상도를 가져오는 간단한 프로그램입니다.

사용자 삽입 이미지

xaml code

<Window x:Class="WPFScreen.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="165" Width="300">
    <Grid>
        <Label HorizontalAlignment="Left" Margin="23,30,0,0" VerticalAlignment="Top"
               Width="55" Height="23" Content="Width :"/>
        <Label HorizontalAlignment="Left" Margin="23,0,0,38" VerticalAlignment="Bottom"
               Width="55" Height="23" Content="Height : "/>
        <TextBlock Margin="78,35,137,0" TextWrapping="Wrap" x:Name="txWidth"
                   VerticalAlignment="Top" Height="23" />
        <TextBlock Margin="82,0,133,33" TextWrapping="Wrap" VerticalAlignment="Bottom"
                   Height="23" x:Name="txHeigh" />
    </Grid>
</Window>
 

cs code

using System.Windows;
 
namespace WPFScreen
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
 
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
        }
 
        void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            txWidth.Text = SystemParameters.PrimaryScreenWidth.ToString();
            txHeigh.Text = SystemParameters.PrimaryScreenHeight.ToString();
        }
    }
}

Aero Glass(에어로 글래스) 사용하기

WPF에서 에어로 글래스를 사용하기 위해서는 DwmExtendFrameIntoclientAero API를 호출해야 합니다.

 참고 : DWM : DeskTop Window Manager

윈도우의 투명색은 다른 여러가지 색으로도 변경이 가능하며 무채색으로도 효과를 줄 수 있습니다. DeskTop Window Manager 사용하기 위해서는 PInvoke(Platform Invoke)를 사용해야 합니다. WPF에 관리되지 않는 코드이기 때문에 Win32의 API를 호출해야 합니다.

using System.Runtime.InteropServices;

네임스페이스에 Win32 API를 호출하기 위한 네임스페이스를 선언합니다.

[DllImport("dwmapi.dll", PreserveSig = false)]
static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
 
[DllImport("dwmapi.dll", PreserveSig = false)]
static extern bool DwmIsCompositionEnabled();

C#에서 Win32 Api 호출


xaml code
<Window x:Class="WpfAeroGlass.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="320" Width="480">
    <Grid>
       
    </Grid>
</Window>


AeroGrassHelper
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
 
using System.Runtime.InteropServices;
using System.Windows.Interop;
 
namespace WpfAeroGlass
{
    public class AeroGlassHalper
    {
        public struct MARGINS
        {
            public MARGINS(Thickness t)
            {
                Left = (int)t.Left;
                Right = (int)t.Right;
                Top = (int)t.Top;
                Bottom = (int)t.Bottom;
            }
 
            public int Left;
            public int Right;
            public int Top;
            public int Bottom;
        }
 
        [DllImport("dwmapi.dll", PreserveSig = false)]
        static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
 
        [DllImport("dwmapi.dll", PreserveSig = false)]
        static extern bool DwmIsCompositionEnabled();
 
        public static bool ExtendGlassFrame(Window window, Thickness margin)
        {
            if (!DwmIsCompositionEnabled())
                return false;
 
            IntPtr hwnd = new WindowInteropHelper(window).Handle;
            if(hwnd == IntPtr.Zero)
                throw new InvalidProgramException("The Window must be shown before extending glass.");
 
            window.Background = Brushes.Transparent;
            HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent;
 
            MARGINS margins = new MARGINS(margin);
            DwmExtendFrameIntoClientArea(hwnd, ref margins);
            return true;
        }
    }
} 

window.Background = Brushes.Transparent;
HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent;
위의 코드는 WPF와 Win32 모두 투명한 배경으로 설정합니다.

cs code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
 
namespace WpfAeroGlass
{
    ///<summary>
    /// Window1.xaml에 대한 상호 작용 논리
    ///</summary>
    public partial class Window1 : Window
    {
        private bool neverRendered = true;
 
        public Window1()
        {
            InitializeComponent();
 
            this.SourceInitialized += new EventHandler(Window1_SourceInitialized);
        }
 
        void Window1_SourceInitialized(object sender, EventArgs e)
        {
            AeroGlassHalper.ExtendGlassFrame(this, new Thickness(-1));
        }
 
        protected override void OnContentRendered(EventArgs e)
        {
            if (neverRendered)
            {
                SizeToContent = SizeToContent.Manual;
 
                FrameworkElement root = this.Content as FrameworkElement;
 
                if (root != null)
                {
                    root.Width = double.NaN;
                    root.Height = double.NaN;
                }
 
                this.neverRendered = false;
            }
 
            base.OnContentRendered(e);
        }
 
    }
}
 

AeroGlassHalper 클래스의 ExtendGlassFrame메소드는 윈도우의 크기를 확장할때 그 크기에 맞추어 에어로 글래스 효과를 줄지 결정하는 역활을 합니다. 윈도우의 모든 영역을 투명창으로 하려면 -1를 넘겨줍니다. 인수타입은 Thickness 입니다.

오버라이드 된 OnContentRendered 이벤트에서 base.OnContentRendered(e);를 계속 호출하는 것은 윈도우가 랜더링 될때마다 윈도우의 전체영역에서 투명효과를 주기위해서 입니다.

사용자 삽입 이미지




사용자 삽입 이미지



저의 노트북 바탕화면을 실버라이트 심벌로 해놨습니다.^^ 그 위에 WPF 윈도우창이 에어로 글래스 효과를 주어 반투명창 효과가 나타났고 그 뒤에 윈도우의 배경화면이 보입니다.,

참고 사이트 및 도서
http://blogs.msdn.com/adam_nathan/archive/2006/05/04/589686.aspx (에덤네이선의 블로그)
에덤네이선의 WPF 언리쉬드(참고도서)

※ AeroGrassHelper 의 원본코드의 저작권은 에덤네이선(Adam Nathan)에게 있음을 알려드립니다.

Flash Movie 실행하기

사용자 삽입 이미지

사용자 삽입 이미지

WPF에서 Flash Movie를 재생하는 데모를 만들어보겠습니다. ActiveX 컨트롤 사용하는 방법과 동일하며 AxInterop.ShockwaveFlashObjects.dll 이 필요합니다. dll이 로컬에 존재한다면 참조에 추가하면 되고 없으면 여기에서 다운로드 받으시면 됩니다.


 


AxInterop.ShockwaveFlashObjects.dll이 추가되었습니다.


로컬에 있는 Flash Movie를 가져와 WPF에서 재생을 합니다.


xaml code
<Window x:Class="WPFControlSwf.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="400" Width="400">
    <Grid x:Name="grid">
    </Grid>
</Window>

cs code
using System.Windows;
 
using System.Windows.Forms.Integration;
using AxShockwaveFlashObjects;
 
namespace WPFControlSwf
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
 
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
        }
 
        void Window1_Loaded(object sender, RoutedEventArgs e)
        {
 
            WindowsFormsHost host = new WindowsFormsHost();
 
            AxShockwaveFlash swfPlayer = new AxShockwaveFlash();
            host.Child = swfPlayer;
 
            grid.Children.Add(host);
            swfPlayer.Movie = "c://flash.swf";
            swfPlayer.Play();
        }
    }
}

코드 설명
using AxShockwaveFlashObjects;
Flash 관련 네임스페이스를 선언합니다.

swfPlayer.Movie = "c://flash.swf";
swfPlayer.Play();
Movie프로퍼티는 Flash Movie 경로를 지정하고 Play() 메소드는 WPF 프로그램이 실행될때 Flash Movie를 자동으로 재생하도록 합니다.

Summary  
 전자문서나 전자도서 같은 프로그램에서 모든 콘텐츠를 WPF나 Silverlight로 개발하기에 한계가 있으므로 전자도서의 컨텐츠를 개발했을때 그 컨텐츠를 이용하기 위한 좋은 방법이 될것입니다. 제가 얼마전에 참여했던 디지털 교과서가 그 좋은 예라 할수 있습니다. 그리고 ActiveX로 개발된 컨텐츠라면 그 어떤것도 WPF에서 실행할 수가 있습니다.  

ActiveX 컨트롤 사용하기

WPF From 내부안에 긍즉적으로 다른 윈도우가 종속족으로 퐇마될 수 없습니다. 그러나 이를 가능하게 해주는 클래스가 지난 강좌(WPF에서 윈폼 컨트롤 클래스 사용히기)에서 다루었던 ElementClass입니다. Element 클래스를 이용하여 ActiveX를 컨트롤할 수 있는데요


ActiveX 컨트롤 추가하는 방법
1. ActiveX Importer(AXIMP.EXE)를 실행
(이 유틸리티는 윈도우즈 SDK의 닷넷컴퍼넌트에 포함되어 있습니다.)
  
2. Visual Studio에서 윈폼 프로젝트를 만든다음 [도구상자]-[항목선택]을 한다음 [도구상자선택항목]의 [COM 구성요소]템에 있는 ActiveX를 선택하여 도구상자에 추가한다음 이 컨트롤을 윈폼에 마우스로 드레그하여 추가하는 방법(추가하면 윈폼에서 자동으로 실행됩니다.)

이 강좌에서는 2번째 방법을 택하여 ActiveX를 추가해보겠습니다.

 



윈도우 미디어 플레이어 ActiveX를 추가하였습니다.

 

드레그 하여 윈폼에 추가합니다. 어쨌든 여기서 필요한 건 AxWMPLib.dll과 WMPLib.dll 이기 때문에 윈폼 프로젝트의 참조된 두개의 dll을 그대로 WPF 프로젝트의 참조에 추가해줍니다.

xaml Code

<Window x:Class="WPFActiveX.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="515" Width="450">
    <Grid x:Name="grid">
        
    </Grid>
</Window>

using System.Windows;
using System.Windows.Controls;
 
using System.Windows.Forms.Integration;
 
namespace WPFActiveX
{
    ///<summary>
    /// Window1.xaml에 대한 상호 작용 논리
    ///</summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
 
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
        }
 
        void Window1_Loaded(object sender, RoutedEventArgs e)
        {
 
            grid.BeginInit();
 
            grid.Height = 500;
            grid.Width = 480;
 
            RowDefinition row = new RowDefinition();
            row.Height = new GridLength(450);
            grid.RowDefinitions.Add(row);
 
            row = new RowDefinition();
            row.Height = GridLength.Auto;
            grid.RowDefinitions.Add(row);
 
            AxWMPLib.AxWindowsMediaPlayer axWmp = new AxWMPLib.AxWindowsMediaPlayer();
            WindowsFormsHost host = new WindowsFormsHost();
            host.Child = axWmp;            
           
            TextBox txtUrl = new TextBox();
            txtUrl.Text = @"mms://wm.microsoft.com/ms/korea/etc/vs2008_1_Opening.wmv";
 
            string wmpURL = txtUrl.Text.ToString();
 
            grid.Children.Add(host);
            grid.Children.Add(txtUrl);
 
            Grid.SetRow(host, 0);
            Grid.SetRow(txtUrl, 1);
 
            axWmp.uiMode = "mini";
 
            axWmp.URL = wmpURL;
        }
    }
} 

코드설명은 ActiveX 부분만 간단히 설명하겠습니다.
AxWMPLib.AxWindowsMediaPlayer axWmp = new AxWMPLib.AxWindowsMediaPlayer();

위 코드는 윈도우 미디어 플레이어 ActiveX를 사용하기 위해 추가된 dll을 인스턴스 생성하는 부분입니다.

 axWmp.uiMode = "mini";
 
 axWmp.URL = wmpURL;

uiMode 프로퍼티는 윈도우 플레이어가 실행될때 열림상태를 정의 합니다. URL은 스트리밍 되는 동영상의 주소입니다. 로컬 및 온라인에 있는 동영상 모두 재생이 가능합니다.

Summary  
 WPF에서 ActiveX를 컨트롤 할 일은 그렇게 많지 않겠지만 기존에 개발된 ActiveX를 사용해야 한다면 좋은 대안이 될 수 있을 것입니다.

참고 사이트

윈폼(Winform) 컨트롤 사용하기

WPF에서 윈폼 컨트롤을 사용하기 위해서는 ElementHost라는 클래스를 통해서 윈폼 컨트롤을 WPF에 포함할 수 있습니다. ElementHost 클래스는 HwndSource와 같지만 임의의 HWND보다는 WPF 내부에 윈폼의 컨트롤을 포함시킬 수 있도록 특화도니 클래스입니다.  ElementHost 호스트는 using System.Windows.Controls을 상속받아 윈폼 컨트롤을 WPF 컨텐트(Content) 내부에 어떻게 보여줄지를 결정합니다.

[도구상자]-[항목선택]순으로 메뉴를 열면 [도구상자선택항목] 대화상자에서 ElementHost가 선택되어 있거나 선택하면 [도구상자]에 WindowsFormsHost 컨트롤이 추가된 것을 볼 수 있습니다.




using System.Windows;

using System.Windows.Controls;

 

using System.Windows.Forms.Integration;

 

namespace WPFWindowsFormsHost

{

    /// <summary>

    /// Window1.xaml에 대한 상호 작용 논리

    /// </summary>

    public partial class Window1 : Window

    {

        public Window1()

        {

            InitializeComponent();

 

            // WPF Expander Control 생성

            Expander expander = new Expander();

            expander.Header = "WPF WindowsFormsHost";

 

            // 컨트롤을 생성하고 이를 WindowsFormsHost에 매핑한다.

            WindowsFormsHost host = new WindowsFormsHost();

            host.Child = new System.Windows.Forms.MonthCalendar();

 

            // Expender Content프로퍼티에 WindowsFormsHost 인스턴스 생성

            expander.Content = host;

 

            // Root Element Expender을 추가한다.

            this.Content = expander;

        }

    }

}


네임스페이스에 using System.Windows.Forms.Integration를 추가하면 ElementHost 클래스를 인스턴스 할 수 있습니다. ElementHost 클래스에 있는 Child 프로퍼티는 윈폼의 컨트롤을 포함하게 하여 WPF에서 윈폼컨트롤을 보여지게 할 수있습니다.

Child 프로퍼티에 윈폼의 달력 컨트롤을 인스턴스하여 생성하면 화면에 달력이 보여지게 됩니다.



참고사이트 : http://www.danielmoth.com/Blog/2007/10/wpf-and-windows-forms-integration.html
참고도서 : 애덤 네이선의 WPF 언리쉬드

News Reader SDK 공개

Introducing the Syndicated Client Experiences Starter Kit & Reader SDK 라는 제목으로 미국마이크로소프트 공식 사이트에 소개되어 있습니다.

URL: http://windowsclient.net/wpf/starter-kits/sce.aspx

NY Times Reader와 Seattle PI Reader 의 원 소스였던, News Reader SDK가 공개되었습니다.

클래스를 상속받아 윈도우 응용 프로그램 구현하기

보통 Application 클래스를 상속받아 윈도우 응용프로그램을 만들 수도 있지만 Window 클래스를 상속받아 윈도우 응용프로그램을 만드는 것도 가능합니다.

 Window 클래스를 상속받아 하나의 파일에서 정의하는 것이 조금 더 일반적이며 더 쉬운 방법이라고 할 수 있습니다.

using System;
using System.Windows;
using System.Windows.Input;
 
namespace Chapter1
{
    class InheritTheWin : Window
    {
        [STAThread]
        public static void Main()
        {
            Application app = new Application();
            app.Run(new InheritTheWin());
        }
 
        public InheritTheWin()
        {
            Title = "Inherit the Win";
        }
    }
}

Main 함수에서 Application 클래스를 인스턴스 하고 Window 클래스를 상속받은 InheritTheWin 클래스를 새로 생성합니다.

Application app = new Application();
app.Run(new InheritTheWin());

위 구문을 더 간단히 할 수 있는 방법이 있습니다. 구문은 다음과 같습니다. Main 함수안에 위의 코드를 주석처리 하고 아래코드를 삽입하면 됩니다.

new Application().Run(new InheritTheWin());

new 키워드를 이용하여 Application 객체를 생성하고 Application 클래스에 들어 있는 Run 메소드 안에 Window 클래스를 상속받은 InheritTheWin 클래스를 생성하여 윈도우를 오픈합니다.

기존에 Application 클래스를 상속 받아서 처리할때보다 코드가 아주 쉽고 간편합니다.

참고서적 : 찰스 페졸트의 WPF

Color와 Colors 구조체를 객체 생성 및 색 지정

WPF에서 색상을 다루기 위해서는 System.Windows.Media 네임스페이스에 정의된 Color 구조체를 사용합니다. Color 구조체는 빛의 3원색인 빨간색, 녹색, 파란색 3가지를 사용합니다. 이 3원색은 영문의 앞자를 따서 R(Red), G(Green), B(Blue)로 나타냅니다. 또 색상의 투명도를 나타내는 알파 채널을 추가하여 ARGB라고 표현합니다. 약자는 A(Alpha)로 나타내며 값이 0이면 완전한 투명하다는 의미이며 255이면 불투명임을 나타냅니다.
 
3원색을 나타내기 위해서 다음과 같이 코드를 작성합니다. Color 구조체는 인자가 있는 객체와 없는 객체가 모두 존재합니다.

인자 값이 없는 Color 객체 생성


Color color = new Color();
 
color.R = 255;
color.G = 0;
color.B = 0;

 
Color 구조체에서 지원하는 정적 메소드를 있습니다. 이 경우 3개의 인자 값이 필요하며 데이터 타입은 Byte이며 0~255까지 입력 가능합니다.  
 

Color color = Color.FromRgb(0, 255, 255);
 

다음은 알파채널 지정할 수 있는 메소드 사용법입니다. A값 역시 0~255까지 입력 가능하며 데이터타입은 Byte형입니다.


Color color = Color.FromArgb(255, 0, 255, 255);
 

지금까지 설명한 내용은 Color 구조체에 객체를 생성하여 0~255까지의 Byte 값을 인자값으로 직접 대입하는  방법을 사용하는 경우이며 System.Windows.Media에는 Colors란 이름의 클래스도 있는데, 여기에는 알파벳순으로 지정된 읽기 전용의 141개 정적 프로퍼티가 있습니다. 사용법은 다음구문과 같습니다.


Colors color = Colors.YellowGreen;
 
 
마지막으로 가장 중요한 것은 Color 객체는 색을 지정할 경우 직접 대입할 수 없기 때문에, 가장 널리 사용되는 Brush 타입의 객체를 사용합니다.
 
일반적으로 색을 대입할 때 SolidColorBrush 클래스를 이용하여 Window의 background나 각종 Control의 색을 지정할 수 있습니다. 사용방법은 다음구문과 같습니다.
 

1)
Color color = Color.FromRgb(0, 255, 255);
SolidColorBrush brush = new SolidColorBrush(color);
Background = brush;

2)
Background = new SolidColorBrush(Color.FromRgb(0, 255, 255));

3)
SolidColorBrush brush = new SolidColorBrush();
brush.Color = Color. FromRgb(0, 255, 255);
 

다음강좌에는 Gradient를 그릴 때 사용하는 RadialGradientBrush,
LinearGradientBrush 클래스에 대해여 예제를 통해 자세히 알아보겠습니다.

참고서적 : 찰스 페졸트의 WPF

화면에서 윈도우 크기와 위치 지정

사용자 삽입 이미지
윈도우 운영체제에서 창은 화면상에 표시되는 위치와 크기를 갖는데 이를 재지정 할 수 있습니다. 크기(Size) : Width(가로), Height(세로)
 
Window 클래스는 FrameworkElement로부터 Width와 Height 프로퍼티를 상속 받습니다. 따라서 다음처럼 다음과 같이 생성자에서 이 프로퍼티의 값을 재정의 할 수 있습니다.

사용자 삽입 이미지

 
Width와 Height는 초기에는 정의돼 있지 않으며 프로그램에서 따로 정의하지 않는 한 계속 이런 상태로 남습니다. 따라서 이를 달리 표현하면 NaN(숫자가 아님:not a number)값을 갖게 합니다.
 
창의 실제 크기를 얻기 위해서는 Width와 Height 프로퍼티를 사용해서는 안 되며 ActualWdith, ActualHeight 프로퍼티를 사용해야 합니다. 초기에는 값이 0이며 창이 화면에 표시된 후에 실제 값을 갖게 됩니다.
 
WPF에서는 모든 크기나 위치를 지정할 때 장치 독립적 픽셀(device-independent pixels) 또는 논리 픽셀(logical pixels)이라고 하는 단위를 사용합니다. 이 단위는 1/96인치이며, 예를 들어서 Width가 288이고 Height가 192의 값을 갖는다면 실제로 창의 가로가 3인치이고 세로가 2인치임을 의미합니다. 이는 모든 컴퓨터의 설정에 따라 차이가 있을 수 있으며 사용자가 윈도우의 설정을 변경이 변경 가능하기 때문입니다.
 
모니터의 설정에서 기본값으로 96DPI(인치당 도트 수, dots per inch)로 설정돼 있으며 그런 경우 Width와 Height는 각각 288과 192가 그대로 픽셀 값과 일치 합니다. 그러나 120DPI로 설정이 변경한다면 Width와 Height 프로퍼티가 288, 192인 경우에 실제 픽셀 수가 360과 240이 되는 것입니다. 픽셀이 아닌 실제 창의 크기는 변함이 없습니다. 미래의 모니터는 지금보다 더 높은 해상도를 표시하므로 DPI의 수치는 높을 것이고 따라서 창의 실제 크기는 동일하게 변함이 없을 것입니다.
 
 
 
Width와 Height의 값을 매우 작은 값을 넣어 시험해보면 다음그림처럼 창의 제목표시줄은 항상 특정 크기보다 작아지지 않는다는 사실을 발견할 수 있습니다.

 
사용자 삽입 이미지
 
이런 창의 크기는 정적 읽기 프로퍼티인 SystemParameters.MinimizedWindowHeight와 SystemParameters.MinimizedWindowWidth에 저장돼 있습니다. SystemParameters 클래스에는 이 같은 몇가지 정적 프로퍼티가 있습니다.
 
화면의 위치를 결정짓는 값은 Left와 Top에 들어 있으며, 프로그램에서 이 프로퍼티를 변경하지 않으면 NaN의 값이 유지됩니다. 윈도우의 해상도에 대한 값은 정적 프로퍼티인 SystemParameters.PrimaryScreenWidth와 SystemParameters.PrimaryScreenHeight의 값을 통해 알 수 있습니다. DPI값에 따라 각각 값이 변경될 수 있습니다.
 
SystemParameterssms는 모두 크기를 장치 독립적 단위로 표현하지만 유일하게 SystemParameterssms의 프로퍼티중 SmallIconWidth와 SmallIconHeight는 픽셀 단위입니다. 대부분의 값들은 별다른 변환 없이 바로 사용할 수 있으며, 예를 들어 창을 화면의 우측하단 영역에 위치시키기 위해 다음과 같이 할 수 있습니다.

SystemParameters.PrimaryScreenWidth - Width;
Top = SystemParameters.PrimaryScreenHeight - Height;

윈도우 영역의 작업표시줄을 감안한다면 코드는 다음과 같습니다. SystemParameters.WorkArea 프로퍼티는 Rect 타입의 객체를 반환합니다. 이 타입은 왼쪽 상단의 위치와 크기로써 사각형을 정의하는 구조체입니다.

Left = SystemParameters.WorkArea.Width - Width;
Height = SystemParameters.WorkArea.Height - Height;

WorkArea를 감안하여 화면의 중앙에 창을 위치코자 한다면 코드는 다음과 같습니다.

Left = (SystemParameters.WorkArea.Width - Width) / 2 +
SystemParameters.WorkArea.Left;
Height = (SystemParameters.WorkArea.Height - Height) / 2 +
      SystemParameters.WorkArea.Top;

이 코드를 Window 클래스에 정의된 WindowStartupLocation 프로퍼티를 사용해 바꿀 수 있습니다.

사용자 삽입 이미지

WindowStartupLocation 열거형의 멤버를 이 프로퍼티에 대입합니다. 기본값은
WindowStartupLocation.Manual로, 프로그램이나 윈도우 운영체제에서 수동으로 창의 위치를 지정합니다. WindowStartupLocation.CenterScreen으로 지정하면 창을 화면의 중앙에 위치킵니다. 세 번째로 WindowStartupLocation.CenterOwner가 있는데 모달 대화상자를 그 소유자의 중앙에 위치시킵니다.

 

Application의 window 제어하기

윈도우용 데스크톱 프로그램은 한 번에 여러 개의 창을 띄울 수 있다는 것을 여러분은 익히 알고 있을 것입니다. 그 중 특정 윈도우를 닫으면 현재 열려있는 윈도우가 닫히고 최종적으로 프로그램이 완전히 종료하게 됩니다. 여러 개의 윈도우중 그 어느 윈도우를 닫더라도 현재 실행중인 프로그램이 종료된다면 프로그램의 성능상에 심각한 문제가 발생 할 수 있습니다. 또 프로그램에는 반드시 메인 윈도우가 존재해야 하며 서브 윈도우를 제어할 수 있어야 합니다.
using System;
using System.Windows;
using System.Windows.Input;
 
namespace Chapter1
{
    class ThrowWindowParty : Application
    {
        [STAThread]
        public static void Main()
        {
            ThrowWindowParty app = new ThrowWindowParty();
            app.Run();
        }
 
        protected override void OnStartup(StartupEventArgs e)
        {
            Window winMain = new Window();
            winMain.Title = "Main Window";
            winMain.MouseDown += new MouseButtonEventHandler(winMain_MouseDown);
            winMain.Show();
 
            for (int i = 0; i < 2; i++)
            {
                Window win = new Window();
                win.Owner = winMain;
                win.Title = "Extra Window No." + (i + 1);
                win.Show();
            }
        }
}
}

위 프로그램에서 첫 번째 중요한 사실은 OnStartup() 이벤트에서 생성된 3개의 창은 이 응용프로그램에서 모두 동등하다는 것입니다. 그 어떤 윈도우라도 클릭하게 되면 선택된 윈도우는 가장 앞에 자리하게 됩니다. 어떤 순서로도 닫을 수 있으며 가장 마지막에 윈도우가 닫히면 프로그램은 종료됩니다.

 그러나 여기서 간과할 수 없는 것은 Application 객체의 MainWindow 프로퍼티를 살펴보면, Show가 호출되는 첫 창이 그 응용프로그램에서 메인 윈도우로 간주되는 것을 알 수 있습니다.

 프로그램을 실행시켜 보면 윈도우 작업 표시줄에 3개의 윈도우가 모두 표시되 있는 것을 확인할 수 있습니다.

사용자 삽입 이미지

for 루프 안에 다음 구문을 삽입하면 "Main Window" 란 제목을 가진 윈도우만 남게 됩니다.

for (int i = 0; i < 2; i++)
{
Window win = new Window();
    win.Owner = winMain;
    win.Title = "Extra Window No." + (i + 1);
    win.ShowInTaskbar = false;
    win.Show();
}

그러나 이 같은 경우 "Main Window" 윈도우를 닫을 경우 윈도우 작업표시줄에 있던 항목은 사라지지만 여전히 응용 프로그램은 계속 실행중 입니다. 물론 2개의 다른 창도 그대로 프로세스에 남아있겠지요 ~~~

 일반적으로 윈도우 프로그램은 Run 메소드가 반환될 때 프로그램이 종료되는데, 마지막 윈도우를 닫을 경우 Run메소드가 반환됩니다. 만약 메인윈도우가 지정되고 이 윈도우가 닫힐 경우만 프로르램이 종료되도록 설정하고 싶다면 Application 클래스의 ShotdownMode 프로퍼티를 OnMainWindowClose로 설정하면 됩니다. (기본값은 OnLastWindowClose 입니다)

ShutdownMode
프로퍼티


ShutdownMode

OnLastWindowClose

마지막 윈도우가 닫힐 경우

OnMainWindowClose

메인 윈도우를 닫을 경우

OnExplicitShutdown

Shutdown 메소드를 명시적으로 호출할 경우

 윈도우 응용프로그램의 시작점인 Main() 메소드에서 상속받은 Application 클래스안에 있는 ShutdownMode 프로퍼티를 사용하면 됩니다. 여기서 중요한 것은 Run메소드가 실행되기 전에 ShutdownMode 프로퍼티가 설정되어야 합니다.

[STAThread]
public static void Main()
{
ThrowWindowParty app = new ThrowWindowParty();
    app.ShutdownMode = ShutdownMode.OnMainWindowClose;
    app.Run();
}

반면 재정의(override) OnStartup 이벤트 안에서는 this 키워드만 붙이면 이벤트 안의 어느곳이든 ShutdownMode 프로퍼티 설정이 가능합니다. (this 키워드는 생략할 수 있으므로 그냥 프로퍼티 이름만 적어도 됩니다.)

protected override void OnStartup(StartupEventArgs e)
{
     Window winMain = new Window();
     winMain.Title = "Main Window";
     winMain.MouseDown += new MouseButtonEventHandler(winMain_MouseDown);
     // this.ShutdownMode = ShutdownMode.OnMainWindowClose;
     ShutdownMode = ShutdownMode.OnMainWindowClose;
     winMain.Show();
 
    ……… 생략
 }

이제 메인 윈도우가 닫힐 때만 Run 메소드가 반환되고 프로그램이 종료됩니다. 마지막으로 메인윈도우를 지정하는 구분을 알아보면 다음과 같습니다. 다음 구문을 OnStartup 이벤트의for 루프 안에 추가합니다.

MainWindow = win;

마지막으로 지금까지 추가된 모든 구문을 제거하고 여러 윈도우들에 대한 계층 구조를 만드는 또 다른 방법을 알아보겠습니다. For 루프 안에 다음 구문을 추가합니다. Window 클래스에 정의된 Owner 프로퍼티를 이용하여 메인으로 지정할 윈도우를 지정하는 합니다. Owner은 소유자라는 뜻으로 기본값은 null 이며 나머지 윈도우를 소유하고 제어할 수 있습니다. 소유자 윈도우를 최소화하면 모든 윈도우가 화면에서 사라지고 소유자 윈도우를 닫으면 나머지 모든 윈도우도 자동으로 닫히게 됩니다.

Win.Owner = winMain;

 참고서적 : 찰스 페졸트의 WPF

이벤트 안에서 현재의 윈도우 객체 구하기

WPF 이벤트 안에서 현재의 윈도우 객체 구하기

※ 코드예제는 찰스 페졸트의 WPF에서 참고하였습니다.

using system;
using system.windows;
using system.windows.input;
 
namespace chapter1
{
    class handleanevent
    {
        [stathread]
        static void main()
        {
            application app = new application();
 
            window win = new window();
            win.title = "handle an event";
            win.mousedown += new mousebuttoneventhandler(win_mousedown);
 
            app.run(win);
        }
 
        static void win_mousedown(object sender, mousebuttoneventargs args)
        {
            // window win = sender as window;
 
            // application 클래스의 특정 프로퍼티를 사용
            // application에는 current란 정적 프로퍼티가 있는데, 이 프로퍼티는
            // 프로그램이 생성한 application 클래스를 반환한다.
            // 또한 application은 window 객체를 반환하는 mainwindow란 이름의 인스턴스 프로퍼티를 갖고 있다.
            // 따라서 이벤트 핸들러에서 다음과 같은 방법으로 window 타입의 지역 변수를 할당할 수 있다.
            window win = application.current.mainwindow;
            string strmessage =
                string.format("window clicked with {0} button at point ({1})",
                    args.changedbutton, args.getposition(win));
            messagebox.show(strmessage, win.title);
        }
    }
}

이벤트의 얻은 현재의 윈도우 object의 값 sender을 변환하는 방법도 있으나 동일한 Window 객체를 이벤트 핸들러 안에서 구하는 방법도 있습니다.

object
값의 senderWindow로 변환하는 방법

Static void win_mousedown(object sender, mousebuttoneventargs args)
{
    window win = sender as window;
}

Main에서 생성된 Window 객체는 정적 필드로 저장돼, 이벤트 핸들러에서 이를 사용할 수 있습니다.

동일한 Window 객체를 이벤트 핸들러 안에서 구하는 방법

Static void win_mousedown(object sender, mousebuttoneventargs args)
{
window win = application.current.mainwindow;
}

Application 클래스의 특정 프로퍼티를 사용해도 되는데 Application에는 Current란 정적 프로퍼티가 있는데, 프로퍼티는 프로그램이 생성한 Application 클래스를 반환합니다. 또한 Application Window 객체를 반환하는 MainWindow란 이름의 인스턴스 프로퍼티를 갖고 있습니다. 따라서 이벤트 핸들러에서 위와 같은 방법으로 Window 타입의 지역 변수를 할당할 수 있습니다.

이벤트 안에서 현재의 윈도우 객체를 얻을 때 아주 유용한 코드입니다.

※참고
프로퍼티 : 오브젝트가 가지고 있는 속성


참고서적 : 찰스 페졸트의 WPF

응용프로그램 Application 클래스 이벤트 처리

WPF 응용 프로그램에서 Application 클래스의 이벤트들을 처리할 필요가 있다면 해당하는 이벤트에 대한 이벤트 핸들러를 설치해야 하지만, 가장 편리한 방법은 Application 클래스를 상속하는 클래스를 정의하는 방법입니다.

using System;

// Application 클래스를 포함하는 Namespace 선언
using System.Windows;
using System.Windows.Input;
 
namespace Chapter1
{
    // Application 클래스 상속
    class InheritApp : Application
    {
        [STAThread]
        public static void Main()
        {
InheritApp app = new InheritApp ();
            app.Run();
        }
 
        // Application을 상속받은 클래스에서는 발생된 이벤트를
        // 처리하는 기본 메소드들을
오버라이딩 할 수 있다.
        protected override void OnStartup(StartupEventArgs e)
        {
            // 처리 루틴
        }
 
        protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
        {
            // 처리 루틴
        }
    }
}

 

클래스 계층 구조

WPF의 모든 클래스는 Object 로부터 상속을 받으며 Application이 실행되면 onStartup() 이벤트가 override되어 프로그램이 시작됩니다. 실제 우리 눈에 보이는 Window 클래스까지 여러단계를 거쳐... Window에 여러 Control을 표시합니다.

WPF 공부를 하시는 모든분들은 위 그림의 계층구조를 계속해서 접하시게 될겁니다. 하나하나 구조를 파악하면서 프로그래밍을 하다보면 WPF 클래스의 계층간 관계나 구조를 자연스럽게 파악하실 수 있을것입니다. 1년전에는 기본 컨트롤 위주로 Markup Language 즉 XAML을 가지고 강좌를 진행했습니다.

조만간에 진행될 WPF 강좌는 XAML과 실제 동적으로 C#코드로도 구현하는 방법을 통하여 WPF 프로그래밍을 하는 방법을 강좌로 통하여 진행해 보도록 하겠습니다.

사용자 삽입 이미지

[XPS] Fxied Documents

XPS(XML Paper Specification)net Framework 3.0과 Windows Vista가 출시되면서 MS에서 밀고 있는 새로운 형태의 전자출판 문서형식입니다. 대표적인 전자출판 문서파일은 Adobe사의  PDF(portable document format)가 있습니다.

XPS는 크게 Fixed Documents와 Flow Documents 2가지 형태로 나누어 집니다. 이번강좌에서는 Fixed Documents에 대해 알아보겠습니다. Fixed Documents는 Read-Only의 읽기전용이며 용도는 XPS로 출판하여 보고서 형태의 기안을 작성한다거나 보안을 걸어서 특정사람에게만 열어보게 할 수도 있습니다.  

XPS 문서를 보려면 XPS DocumentViwer Control이 필요합니다.

XPS 문서형태는 Package형태로 여러가지 파일의 묶음입니다. Package안에는 XML, Image, Font등의 여러가지 파일이 Zip 파일 형태의 데이터 집합입니다.

XPS문서를 열어보면 [그림 2]에서 보시는 것처럼 각각의 폴더를 열어보시면 XML이 존재하고 여기에 들어가는 Image, Font 등의 Resource가 들어가고 Image, Font등의 Content Type을 정의하는 Text 파일이 존재합니다.

사용자 삽입 이미지

그림 1. 압축풀기

사용자 삽입 이미지

그림 2.XPS파일 Package

XPS Documents를 handling하기 위해서는 ReachFramework라는 어셈블리(Assembly)를 추가해야 합니다.

사용자 삽입 이미지


그림 3. ReachFramework Assembly추가

그리고 비하인드 코드에는 System.Windows.Xps.Packaging를 추가합니다.

using System.Windows.Xps.Packaging;

예제는  XPS문서를 볼 수 있는 XPS Documents Viewer 입니다. 파일메뉴에서 열기메뉴를 실행하면 OpenFileDialog 대화상자가 보여지고 XPS문서를 선택하면 DocumentViewer Control을 통해서 XPF문서를 볼 수 있는 형태의 간단한 프로그램입니다.

그럼 DocumentViewer Control와 메뉴를 추가하는 xaml코드와 OpenFileDialog 생성 및 XpsDocument를 추가하여 DocumentViewer Control에 XPS 문서를 읽기 모드로 출력하는 코드가 들어있는 cs코드를 보시겠습니다.

<Window x:Class="wpf26.Window1"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
="XPS Document Viewer" Height="450" Width="600">
   
   
<Window.CommandBindings>
     
<CommandBinding Command="ApplicationCommands.Open"  />
      <
CommandBinding Command="ApplicationCommands.Close" />
    </
Window.CommandBindings>
   
   
<DockPanel>
     
<Menu Name="MainMenu" DockPanel.Dock="Top">
       
<MenuItem Header="File">
         
<MenuItem Command="ApplicationCommands.Open" Header="Open..." />
           <
MenuItem Command="ApplicationCommands.Close" Header="Close" />
        </
MenuItem>
     
</Menu>
     
     
<Grid DockPanel.Dock="Top">
       
<DocumentViewer Name="docViewer">
       
</DocumentViewer>
     
</Grid>
   
</DockPanel>
</Window>

코드를 보시면 Menu, DocumentViewr Control 추가 및 Open과 Close 이벤트를 CommandBinding에 추가하는 부분이 들어가 있습니다.

CommandBinding에 명령어를 추가하는 부분은 http://msdn2.microsoft.com/en-us/library/ms752308.aspx 를 참고하시면 Commanding 에 대해 좀더 자세한 설명이 나와있습니다.

DocumentViewr Control 코드를 보시면 name에 대한 속성만 설정되어 있는 것을 보실 수 있습니다.

using System;
using
System.Collections;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Data;
using
System.Windows.Documents;
using
System.Windows.Input;
using
System.Windows.Shapes;
using
System.Windows.Media;
using
System.Windows.Media.Imaging;
using
System.Windows.Navigation;
using
System.Windows.Forms;

using
System.Windows.Xps.Packaging;
using
System.IO;

namespace
wpf26
{
   
public partial class Window1 : Window
    {
       
private XpsDocument _xpsDocument;
        private string
_fileName;

        public
Window1() : base()
        {
            InitializeComponent()
;

           
AddCommandBindings(ApplicationCommands.Open,
                OpenCommandHandler)
;

           
AddCommandBindings(ApplicationCommands.Close,
                CloseCommandHandler)
;
       
}

       
private void OpenCommandHandler(object sender,
            ExecutedRoutedEventArgs e)
        {
            OpenFileDialog dig
= new OpenFileDialog();            
           
dig.InitialDirectory = Directory.GetCurrentDirectory();
           
dig.Filter = "Xps Documents (*.xps)|*.xps";
           
dig.FilterIndex = 1;
            if
(dig.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
               
if (_xpsDocument != null)
                    _xpsDocument.Close()
;
                try
               
{
                    _xpsDocument
= new XpsDocument(dig.FileName,
                                       System.IO.FileAccess.Read)
;
               
}
               
catch (UnauthorizedAccessException)
                {
                    System.Windows.MessageBox.Show(
                       
string.Format("Unable to access {0}",
                        dig.FileName))
;
                    return;
               
}

                docViewer.Document
=
                   
_xpsDocument.GetFixedDocumentSequence();
               
_fileName = dig.FileName;
           
}
        }

       
private void CloseCommandHandler(object sender,
            ExecutedRoutedEventArgs e)
        {
           
this.Close();
       
}

       
private void AddCommandBindings(
                ICommand command, ExecutedRoutedEventHandler handler)
        {
            CommandBinding cmdBindings
= new CommandBinding(command);
           
cmdBindings.Executed += handler;
           
CommandBindings.Add(cmdBindings);
       
}
    }
}


OpenCommandHandler 메소드를 보시면 Using System.IO 네임스페이스를 선언하여 OpenFileDialog 클래스를 인스턴스 하여 대화상자를 만들고 _xpsDocument 변수에 XPS 문서를 읽기모드로 읽어와서 DocumentViewer에 보여줍니다.

AddCommandBindings 메소드는 CommandBinding에 Open, Close Command를 추가를 합니다. 그리고 Window1 생성자에서 AddCommandBindings 메소드를 추가하여 실행할 수 있도록 초기화를 합니다.

예제를 실행하면 다음과 같이 보실 수 있습니다.

사용자 삽입 이미지

그림 3. 프로그램 실행

사용자 삽입 이미지

그림 4. XPS 문서 출력

invalid-file



1. XPS Team Blog
    http://blogs.msdn.com/xps/
2. Msdn WPF Documents
   http://msdn2.microsoft.com/en-us/library/ms749165.aspx
3. XPS Specification
   http://www.microsoft.com/whdc/xps/xpsspec.mspx  
4. View and Generate XPS
   http://www.microsoft.com/whdc/xps/viewxps.mspx
5. Msdn Magazine
    http://msdn.microsoft.com/msdnmag/issues/06/01/XMLPaperSpecification/default.aspx
6.훈스닷넷 시샵 김수영님 동영상 강의(MS Visual C# MVP)
   http://www.hoons.kr/SeminarReview.aspx (How to develop XPS with WPF )


다음강좌에는 XPS문서를 편집 및 다양한 형태의 출판에 효과적인 Flow Documents에 대해 알아보겠습니다.


※ 강좌 포스팅후

아직까지 WPF의 막강한 화려함에 가려 그 빛을 못보고 있지만 언론사, 출판업체 같은 곳에서 많은 관심을 보이고 있으므로 향후 이런곳에서 프로젝트를 할 기회가 있다면 분명 충분한 도움이 될 수 있다고 생각합니다. WPF 화려한 것만 신경쓰시지 말고 이런 WPF의 다양한 이면에도 관심을 갖고 공부를 하시면 많은 도움이 되리라 생각됩니다.  


※ 테스트 환경
-----------------------------------------------------------------------------------------
운영체체 : Windows Vista Ultimate 32bit
개발툴 : Microsoft Visual C# Codename "Orcas"
-----------------------------------------------------------------------------------------
 

'닷넷 프로그래밍(~2012)' 카테고리의 다른 글

Ellipse(원) 그리기  (0) 2007.08.23
동적으로 오브젝트 생성  (0) 2007.08.16
실행주기(PageCycle)  (0) 2007.08.14
[XPS] Fxied Documents  (0) 2007.08.10
[XPS] View and Generate XPS  (0) 2007.08.10
[Controls] 25. BulletDecorator  (0) 2007.08.10
Path를 이용한 한글폰트 만들기  (0) 2007.08.09
Silverlight 1.1 설치환경  (0) 2007.07.19

[XPS] View and Generate XPS

[각주:1]

View and Generate XPS

Operating System Download Description


Windows Vista



None Required



XPS documents open within Internet Explorer 7.0 or higher. Any application can generate XPS documents using the Microsoft XPS Document Writer.



Windows XP
Windows Server 2003



Microsoft .NET Framework 3.0



XPS document viewing and generation capabilities are included in Microsoft .NET Framework 3.0.
XPS documents open within Internet Explorer 6.0 or higher.



Windows XP
Windows Server 2003



Microsoft XPS Essentials Pack and Microsoft Core XML Services 6.0**



XPS documents open in a stand-alone viewer application. Any application can generate XPS documents using the Microsoft XPS Document Writer.

'닷넷 프로그래밍(~2012)' 카테고리의 다른 글

동적으로 오브젝트 생성  (0) 2007.08.16
실행주기(PageCycle)  (0) 2007.08.14
[XPS] Fxied Documents  (0) 2007.08.10
[XPS] View and Generate XPS  (0) 2007.08.10
[Controls] 25. BulletDecorator  (0) 2007.08.10
Path를 이용한 한글폰트 만들기  (0) 2007.08.09
Silverlight 1.1 설치환경  (0) 2007.07.19
Slideshow  (0) 2007.07.18