WPF learning 11: Drawing editing tool based on MVVM Light (2), wpfmvvm

Source: Internet
Author: User

WPF learning 11: Drawing editing tool based on MVVM Light (2), wpfmvvm

This article is about how to create a graphic editing tool based on MVVM Light (1 ).

This time the goal is to complete

Two tasks.

Canvas

Effect:

On the canvas, the selection scheme is: directly use the Image as the canvas, and bind the RenderTargetBitmap to the Image source, which can greatly facilitate subsequent Image export functions.

Modify the drag column XAML as follows:

<ScrollViewer  HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Grid.Column="1" Grid.Row="1">    <Canvas  VerticalAlignment="Top" HorizontalAlignment="Left"  Width="{Binding ActualWidth,ElementName=ImageBorder}"  SnapsToDevicePixels="False" Height="{Binding Path=ActualHeight,ElementName=ImageBorder}" Margin="50 50 0 0 " ClipToBounds="True">        <Border Name="ImageBorder" BorderBrush="Black" BorderThickness="1">            <Image Source="{Binding DrawingBitmap}">            </Image>        </Border>    </Canvas></ScrollViewer>

Correspondingly, code must also be added to ViewModel.

private RenderTargetBitmap _drawingBitmap;public RenderTargetBitmap DrawingBitmap{    get { return _drawingBitmap; }    set     {         _drawingBitmap = value;        RaisePropertyChanged("DrawingBitmap");    }}

At this point, the canvas binding is complete.

Now you need to complete the code for adjusting the canvas size. First, add two input boxes in XAML to configure the length and width from the interface:

<TextBlock VerticalAlignment = "Center"> <Run Text = "width: "/> </TextBlock> <TextBox Width =" 50 "Margin =" 0 0 10 0 "Text =" {Binding DrawingAreaWidth, ValidatesOnDataErrors = True, updateSourceTrigger = PropertyChanged} "/> <TextBlock verticalignment =" Center "> <Run Text =" high: "/> </TextBlock> <TextBox Width =" 50 "Margin =" 0 0 10 0 "Text =" {Binding DrawingAreaHeight, ValidatesOnDataErrors = True, updateSourceTrigger = PropertyChanged} "/> <Button Margin =" 10 0 10 0 "Content =" configuration "Command =" {Binding SetDrawingAreaSize} "/>

ViewModel section:

private Int32 _drawingAreaWidth;public Int32 DrawingAreaWidth{    get { return _drawingAreaWidth; }    set     {         _drawingAreaWidth = value;        RaisePropertyChanged("DrawingAreaWidth");    }}private Int32 _drawingAreaHeight;public Int32 DrawingAreaHeight{    get { return _drawingAreaHeight; }    set    {        _drawingAreaHeight = value;        RaisePropertyChanged("DrawingAreaHeight");    }}

Finally, the implementation of Command SetDrawingAreaSize is as follows:

private ICommand _setDrawingAreaSize;public ICommand SetDrawingAreaSize{    get    {        return _setDrawingAreaSize ?? (_setDrawingAreaSize = new RelayCommand(() =>            {                DrawingBitmap = new RenderTargetBitmap(DrawingAreaWidth, DrawingAreaHeight,                    96, 96, PixelFormats.Pbgra32);                var drawingVisual = new DrawingVisual();                using (var context = drawingVisual.RenderOpen())                {                    context.DrawRectangle(Brushes.White, null,                        new Rect(0, 0, DrawingAreaWidth, DrawingAreaHeight));                }                DrawingBitmap.Render(drawingVisual);            }            , () => (DrawingAreaWidth != 0 && DrawingAreaHeight != 0)));    }}

At this point, the effect at the beginning of this section is complete.

Straight Line

The effect is as follows:

Two namespaces need to be introduced in XAML:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"xmlns:command=http://www.galasoft.ch/mvvmlight

After the introduction, we can add three mouse-responsive commands for the Image.

<Image Source="{Binding DrawingBitmap}">    <i:Interaction.Triggers>        <i:EventTrigger EventName="MouseMove">            <command:EventToCommand Command="{Binding MouseMoveCommand}" PassEventArgsToCommand="True" />        </i:EventTrigger>        <i:EventTrigger EventName="MouseDown" >            <command:EventToCommand Command="{Binding MouseDownCommand}" PassEventArgsToCommand="True"/>        </i:EventTrigger>        <i:EventTrigger EventName="MouseUp" >            <command:EventToCommand Command="{Binding MouseUpCommand}" PassEventArgsToCommand="True"/>        </i:EventTrigger>    </i:Interaction.Triggers></Image>

Draw the Line control on the interface, which is used for display during dynamic operations. After the operation is completed, hide the control and draw on the Image.

<Line Stroke="Black" StrokeThickness="1" Visibility="{Binding LineVisibility}" X1="{Binding PositionX1}" X2="{Binding PositionX2}"Y1="{Binding PositionY1}" Y2="{Binding PositionY2}"/>

Add the following attributes to ViewModel: X2, Y1, Y2.

private Visibility _lineVisibility = Visibility.Hidden;public Visibility LineVisibility{    get { return _lineVisibility; }    set    {        _lineVisibility = value;        RaisePropertyChanged("LineVisibility");    }}private Double _positionX1;public Double PositionX1{    get { return _positionX1; }    set    {        _positionX1 = value;        RaisePropertyChanged("PositionX1");    }}

To enable ViewModel to know the current drawing status (straight line, circle, rectangle), add some data binding:

<RadioButton Style="{StaticResource StatusBarButton}" IsChecked="{Binding LineModeEnable}">    <Line X1="0" Y1="0" X2="15" Y2="15" Stroke="Black" StrokeThickness="1"></Line></RadioButton><RadioButton Style="{StaticResource StatusBarButton}" IsChecked="{Binding RectangleModeEnable}">    <Rectangle Width="20" Height="15" Stroke="Black" StrokeThickness="1"></Rectangle></RadioButton><RadioButton Style="{StaticResource StatusBarButton}" IsChecked="{Binding EllipseModeEnable}">    <Ellipse Width="20" Height="20" Stroke="Black" StrokeThickness="1"></Ellipse></RadioButton>

Finally, we will write three commands corresponding to the mouse:

Public ICommand SetDrawingAreaSize {get {return _ setDrawingAreaSize ?? (_ SetDrawingAreaSize = new RelayCommand () => {DrawingBitmap = new RenderTargetBitmap (DrawingAreaWidth, DrawingAreaHeight, 96, 96, PixelFormats. pbgra32); var drawingVisual = new DrawingVisual (); using (var context = drawingVisual. renderOpen () {context. drawRectangle (Brushes. white, null, new Rect (0, 0, DrawingAreaWidth, DrawingAreaHeight);} DrawingBitmap. render (drawingVisual) ;}, () => (Drawin GAreaWidth! = 0 & DrawingAreaHeight! = 0) ;}} private ICommand _ mouseMoveCommand; public ICommand MouseMoveCommand {get {return _ mouseMoveCommand ?? (_ MouseMoveCommand = new RelayCommand <MouseEventArgs> (e) => {PositionX2 = e. getPosition (IInputElement) e. source ). x; PositionY2 = e. getPosition (IInputElement) e. source ). Y ;}, (e) => true) ;}} private ICommand _ mouseDownCommand; public ICommand MouseDownCommand {get {return _ mouseDownCommand ?? (_ MouseDownCommand = new RelayCommand <MouseEventArgs> (e) => {if (LineModeEnable) LineVisibility = Visibility. visible; PositionX1 = e. getPosition (IInputElement) e. source ). x; PositionY1 = e. getPosition (IInputElement) e. source ). Y ;}, (e) => true) ;}} private ICommand _ mouseUpCommand; public ICommand MouseUpCommand {get {return _ mouseUpCommand ?? (_ MouseUpCommand = new RelayCommand <MouseEventArgs> (e) => {var drawingVisual = new DrawingVisual (); using (var context = drawingVisual. renderOpen () {// here-1 is used to eliminate the deviation caused by the canvas boundary, because it is currently fixed, so no data binding is used. If (LineModeEnable) context. drawLine (new Pen (Brushes. black, 1), new Point (PositionX1-1, PositionY1-1), new Point (PositionX2-1, PositionY2-1);} DrawingBitmap. render (drawingVisual); LineVisibility = Visibility. hidden ;}, (e) => true ));}}

Circle

Effect:

XAML code:

<Ellipse Stroke="Black" StrokeThickness="1" Visibility="{Binding EllipseVisibility}"        Canvas.Left="{Binding PositionX1}" Canvas.Top="{Binding PositionY1}"         Width="{Binding ShapeWidth}" Height="{Binding ShapeHeight}"></Ellipse>

Added MouseDown:

if (EllipseModeEnable){    ShapeWidth = ShapeHeight = 0;    EllipseVisibility = Visibility.Visible;}

Move added:

ShapeWidth = Math.Abs(PositionX2 - PositionX1);ShapeHeight = Math.Abs(PositionY2 - PositionY1);

Add Up:

if(EllipseModeEnable)    context.DrawEllipse(new SolidColorBrush(Colors.White), new Pen(Brushes.Black, 1),        new Point(PositionX1 + ShapeWidth / 2 - 1, PositionY1 + ShapeHeight / 2 - 1), ShapeWidth / 2, ShapeHeight / 2);

Rectangle

The code is similar to the circle, so it is omitted.

The next section will enlarge, zoom out, move, and fill the color of the image.

 

Development Environment VS2013,. NET4.5

Source code

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.