[WPF] Canvas Draw Line WPF 2017. 5. 11. 15:56

정말 오랜만에 포스팅을 해 보는 듯..

 

태블릿 환경과 동일하게 CS 프로그램을 구현하던 중..

 

Canvas를 쓸 일이 있어서 처음으로 WPF를 적용하다가 멘붕이 왔다..

 

MouseMove를 통하여 Canvas에 그림을 그리는...

 

단.. 다른 컴포넌트들로 구성된 화면 상단에 보여지는...

 

암만 그려도 이상하게 나오거나 화면이 표출 되지 않았다..

 

결국 해결책은...

 

화면에 표기 되는 UserControl 위에 Canvas를 올리고

 

<Canvas.Background>
            <VisualBrush TileMode="Tile"
                Viewport="0,0,0,0" ViewportUnits="Absolute"
                Viewbox="0,0,0,0" ViewboxUnits="Absolute">
            </VisualBrush>
</Canvas.Background>

 

이 부분을 넣어 봤다.

 

모눈 형태 화면이 보일지 해서 확인을 하는 용도로 썼는데 어라?

 

그림이 그려진다.

 

근데 다시 저걸 지우고 하니 아래 코드가 먹지 않았다.

 


        Point currentPoint = new Point();

        SolidColorBrush brush = new SolidColorBrush(Colors.Blue);

        public UserControl1()
        {
            InitializeComponent();
        }

        private void DrawCanvs_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Line newLine = new Line();
                newLine.Stroke = brush;
                newLine.X1 = currentPoint.X;
                newLine.Y1 = currentPoint.Y;
                newLine.X2 = e.GetPosition(canvas1).X;
                newLine.Y2 = e.GetPosition(canvas1).Y;
                newLine.StrokeThickness = 3;
                canvas1.Children.Add(newLine);
                currentPoint = e.GetPosition(canvas1);
            }
        }

        private void DrawCanvs_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                currentPoint = e.GetPosition(canvas1);
            }
        }

 

결국 스스로 얻은 결론은.. BackGround 설정이 없다면 제대로 표시되지 않는걸로 잠정 결론을 내렸다..

 

불론 Canvas에만 그리기라면 위 코드는 정상적으로 동작한다.

 

WPF 메인->컨트롤->그림 그리기 할 경우에

 

Canvas를 올리고 그 위에 컨트롤들을 올리는 형태로 배치를 하면..

 

 

이런 식으로 그리기가 가능하다.

 

자바에서 Canvas 생각이 나서 구현을 한건데..

 

C#에서 Transform을 구현하고 하면.. 그 아래 컨트롤에 접근 못해 결국 WPF로 하긴 했는데..

 

아... 남은 작업들을 어찌할꼬 ㅠㅠ

[WPF] Resource WPF 2012. 3. 19. 17:05
리소스 내에 우리들은 일반적으로 왠만한 이미지 등과 같은 파일들을 저장하고 이용한다. 다음은 그것을 꺼내어 쓰는 내용이다.

 //System.Drawing.Icon icon = WpfApplication16.Properties.Resources.icon
            System.Drawing.Bitmap bmp = WpfApplication16.Properties.Resources.Penguins;
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            ms.Seek(0, System.IO.SeekOrigin.Begin);
            BitmapFrame frame = BitmapFrame.Create(ms);
            image1.Source = frame;

이미지를 불러서 처리하는 내용을 보면 상단에 아이콘 처리 역시 동일하게 할 수 있음을 볼 수 있다.

하지만 아이콘이 차이가 있다면 WPF에서는 Windows.Media.ImageSource 형식을 이용한다는 것이다.

그래서 MemoryStream을 이용하여 메모리 상에 올려 놓고 이미지 데이터로 인코딩하여 연결 한 것이다.

사운드 재생의 경우 SoundPlayer 클래스를 쓰면 된다. 이 역시 Media.SoundPlayer 아래 있다.
[WPF] DependencyProperty WPF 2012. 3. 19. 16:49

의존성 프로퍼티는 다른 입력 값에 의해 속성 값을 변경해주는 곳에 이용이 된다. 여기에서 애니메이션이나 데이터 바인딩 등에 이용이 되고, 입력 값은 테마, 속성, 데이터바인딩, 내이메이션, 리소스 등의 값을 말하고 있다.

기본 형은 다음과 같다.

public static readonly DependencyProperty PropertyName = DependencyProperty.Register("PropertyName", typeof(Type), typeof(Control),  new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChangedEventName)));

여기에서의 값은 get/set을 이용한 메서드를 이용하여 사용한다.

먼저 TextBlock 두개, TextBox, Button을 하나 생성 해 주고 다음 코드를 실행하면 다른 요소의 속성이 바뀌는 것을 확인 할 수가 있을 것이다.

public static readonly DependencyProperty PropertyName = DependencyProperty.Register("name", typeof(String), typeof(Window1), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnTextChangePropertyChanged)));

        public Window1()
        {
            InitializeComponent();
        }

        public String _txtstring
        {
            get
            {
                return (String)GetValue(PropertyName);
            }
            set
            {
                SetValue(PropertyName, value);
            }
        }

        private static void OnTextChangePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Window1 userNamecontrol = d as Window1;
            string newText = (string)e.NewValue;
            string oldText = (string)e.OldValue;
        

            userNamecontrol.textBlock1.Text = newText;
            userNamecontrol.textBlock2.Text = oldText;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this._txtstring = textBox1.Text;
        }



 

[WPF] Command WPF 2012. 3. 19. 15:40
우리가 일반적으로 알고 있는 커맨드는 메모장의 잘라내기, 복사, 붙이기 등이 있다.

WPF에서는 이러한 내용을 내장형으로 지니고 있으며 RoutedCommand와 RoutedEvent를 통하여 처리를 한다.

다음은 커맨드에 대한 간단한 테스트 코드이다.

<StackPanel>
        <Menu>
            <MenuItem Command="ApplicationCommands.Cut"/>
            <MenuItem Command="ApplicationCommands.Copy"/>
            <MenuItem Command="ApplicationCommands.Paste"/>
        </Menu>
        <TextBox x:Name="txtBox" Height="243" BorderBrush="Black" BorderThickness="2" TextWrapping="Wrap" />
    </StackPanel>

실행을 해 보면 텍스트 박스에 있는 글자를 대상으로 작업한다. 메뉴 아이템에서는 해당 커맨드 내용이 연결 된 것을 확인 할 수가 있다.

다음은 추가적인 Command 들이다.

CancelPrint CorrectionList SaveAs Undo
Close Redo Help Open
Print Replace SelectAll  Copy
ContextMenu Delete New Cut
PrintPreview Save Stop Paste
Properties Find NotACommand  

[WPF] ScrollViewer WPF 2012. 3. 19. 15:08
ScrollView 는 ViewBox와 어찌보면 비슷하다. 하나의 자식 컴포넌트만 올라 올 수 있다.

<ScrollViewer>
        <StackPanel>
        <TextBlock Name="btn1" Width="256" Height="25" VerticalAlignment="Top">1</TextBlock>
        <TextBlock Name="btn2" Width="256" Height="25" VerticalAlignment="Top">2</TextBlock>
        <TextBlock Name="btn3" Width="256" Height="25" VerticalAlignment="Top">3</TextBlock>
        <TextBlock Name="btn4" Width="256" Height="25" VerticalAlignment="Top">4</TextBlock>
        </StackPanel>
    </ScrollViewer>

위 코드를 실행하여 보면 스크롤이 생기면서 뷰 형태를 구성하는 것을 확인 할 수 있다.
[WPF] ViewBox WPF 2012. 3. 19. 15:04
ViewBox에는 올라온 자식 컨트롤러의 내용을 알아서 크기 조절을 해 준다.

<Viewbox Stretch="Fill">
        <Button Name="btn" Width="300" Height="30" VerticalAlignment="Center">test</Button>
</Viewbox>

위의 코드 처럼 버튼을 올리면 ViewBox 전체를 버튼이 채워 폼 크기를 조절 하면 자동으로 바뀌는 것을 확인 할 수 있다.

형태를 달리 하고자 할 경우에는 Stretch의 속성 부분을 바꾸어서 테스트 해 보면 알 수 있을 것이다.
[WPF] Canvs WPF 2012. 3. 19. 14:54
캔버스는 일종의 모눈종이라고 생각하면 될 것이다. 아니면 아무런 설정이 되지 않는 하나의 종이라 생각 하면 될 것이다.

이를 사용 할 때는 다음과 같이 하나씩 그 자체의 좌표를 잡아줘야한다.

<Image Canvas.Left="39" Canvas.Top="79" Height="150" Name="image1" Stretch="Fill" Width="200" Source="/WpfApplication11;component/Penguins.jpg" />

그리고 이미지의 형태를 조절 할 때는 Stretch 속성을 유용하게 이용하면 될 것이다.
[WPF] DockPanel WPF 2012. 3. 19. 14:47
DockPanel 이걸 가만히 보면 자바에서 쓰던 BorderLayout이 생각난다.

동서남북의 명칭으로 위치를 지정하여 레이아웃을 잡던 그런 형태로 기억이 난다. 어디서 많이 본.. 그런 케이스랄까..

코드는 다음과 같다.

<Grid>
        <DockPanel LastChildFill="True">
            <Button DockPanel.Dock="Top">Top</Button>
            <Button DockPanel.Dock="Left">Left</Button>
            <Button DockPanel.Dock="Right">right</Button>
            <Button DockPanel.Dock="Bottom">bottom</Button>
            <Button>center</Button>
        </DockPanel>
    </Grid>
[WPF] Grid Split WPF 2012. 3. 19. 14:43
그리드 스플릿. C#에서 스플릿 컨트롤러를 봤을 것인데 그것을 구현 한 것이다.

그리드 형태의 레이아웃을 먼저 자복 거기에 splitter를 붙여 만든 내용이다.

<Window x:Class="WpfApplication9.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
       
        <StackPanel Background="BurlyWood" Grid.Column="0" Grid.RowSpan="2">
            <TextBlock FontSize="30" Foreground="Blue" TextWrapping="Wrap">left</TextBlock>
        </StackPanel>
       
        <GridSplitter Width="10" Grid.RowSpan="2"></GridSplitter>
       
        <Border Grid.Column="1">
            <TextBlock FontSize="30" Foreground="Blue" TextWrapping="Wrap">Right</TextBlock>
        </Border>
       
        <GridSplitter Grid.Column="1" ResizeDirection="Rows" Height="10" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"></GridSplitter>
        <Border Grid.Row="1" Grid.Column="1" Background="Red">
        <TextBlock FontSize="30" Foreground="Blue" TextWrapping="Wrap">Bottom</TextBlock>
        </Border>
    </Grid>   
</Window>

[WPF] Animation WPF 2012. 3. 19. 14:00

애니메이션 효과 나타내는 코드이다. 버튼을 누르면 스토리보드가 나타났다 사라지고 한다.

리소스 측에 정의 한 내용들의 x:key는 키 값으로 해당하는 스토리 보드를 구분하며 DoubleAnimation의 To는 TargetProperty에 해당하는 대상과 일치하는 내용이다.

XAML 코드는 다음과 같고

<Window x:Class="storyboard_animation.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="296" Width="355">
    <Window.Resources>
        <Storyboard x:Key="show">
            <DoubleAnimation To="300" Duration="0:0:0.5" Storyboard.TargetName="m_board" Storyboard.TargetProperty="Width"/>
        </Storyboard>
        <Storyboard x:Key="hide">
            <DoubleAnimation To="0" Duration="0:0:0.5" Storyboard.TargetName="m_board" Storyboard.TargetProperty="Width"/>
        </Storyboard>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <Button x:Name="btn" Height="20" Content="hide" Click="btn_Click" FontSize="10" FontFamily="돋움체"/>
            <Border x:Name="m_board" Background="LightBlue" CornerRadius="30" Height="242" Width="300"/>
        </StackPanel>
    </Grid>
</Window>

호출을 할 경우에는 var story = this.Resources[key] as Storyboard; 을 이용하여 리소스에서 불러온 후 Begin() 으로 실행을 해 준다.

다른 경우의 샘플 예제를 하나 더 보자. 버튼을 눌렀을 때 각기 나오는 내용이다. 실행을 해 보면 페이드 인 아웃이 되는 것을 확인 할 수가 있다.

<StackPanel Margin="20">
        <!-- Clicking this button animates its opacity. -->
        <Button Name="opacityAnimatedButton" Content="A Button" Click="opacityAnimatedButton_Click">
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Click">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation
                                Storyboard.TargetName="opacityAnimatedButton"
                                Storyboard.TargetProperty="(Button.Opacity)"
                                From="1" To="0" Duration="0:0:5" AutoReverse="True"  />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>


        <!-- Clicking this button animates the opacity of the brush
         used to paint its background. -->
        <Button Content="A Button" >
            <Button.Background>
                <SolidColorBrush x:Name="MyAnimatedBrush" Color="Orange" />
            </Button.Background>
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Click">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation
                                Storyboard.TargetName="MyAnimatedBrush"
                                Storyboard.TargetProperty="(Brush.Opacity)"
                                From="1" To="0" Duration="0:0:5" AutoReverse="True"  />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
    </StackPanel>

윗 버튼은 테두리와 함께 모두 사졌다 나타나며 아래 버튼은 테두리를 유지한 채 배경색들이 바뀌는 것을 볼 수가 있다.