Vectorlight News

  • Chat App Converted to HTML and JQuery
    Sep 08, 2011

    Converted from Silverlight to HTML and Javascript/JQuery is the Vectorlight Chat App. Login using your Vectorlight password to chat using your username and avatar.

  • HTML5 iPhone,Android Big Guns Tower Defense
    Jul 02, 2011

    Big Guns has made the leap from Windows Phone 7 (XNA) to HTML5 so you can now play it on your iPhone, Android and other HTML5 compatible devices.

  • HTML5 Games - Word Poppers and Batty
    Jun 04, 2011

    As the take-up of HTML5 quickens (74% of users currently have a browser capable of HTML5 Canvas) we present two more games for both your browser and mobile.

  • Big Guns Tower Defense on Windows Phone 7
    May 06, 2011

    Coming soon to Windows Phone 7 is an XNA port of the popular Vectorlight tower defense game Super Tower Defense. Whilst retaining many of the graphical and gameplay features of the original Silverlight game.

  • Wakacube WP7 Update
    Apr 26, 2011

    Released to the Windows Phone 7 marketplace today is Version 1.1 of Wakacube the 3D physics game of skill. Included in the update are more levels (30 in total) and new mode Wakatime which generates random crate structures to keep players entertained long after the levels have been completed.

  • Home Page News

Creating an Image Resizing Dialog

The RichTextBox by default does not have support for image resizing built in.  To achieve this you can make use of the ImageDoubleClick event that is present in the RichTextBox (and RichTextBlock) to present the user with a Dialog allowing the image to be resized.


A RichTextBox with Image

The Image Resizing User Control

We have a single User Control that contains the Image preview and scale controls.

<UserControl x:Class="RichTextBoxImageEdit.ImageViewer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:liquid="clr-namespace:Liquid;assembly=Liquid"
    >
    <Grid x:Name="LayoutRoot" Margin="0 2 0 0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="360" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <ScrollViewer x:Name="ElementViewer" Grid.Column="0" Padding="0" HorizontalScrollBarVisibility="Auto" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
        <Grid Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="70" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="4" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="32" />
                <RowDefinition Height="32" />
                <RowDefinition Height="32" />
                <RowDefinition Height="32" />
                <RowDefinition Height="32" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBlock Grid.Column="0" Grid.Row="1" Margin="0 0 4 0" Text="Filename:" HorizontalAlignment="Right" />
            <TextBlock x:Name="ElementFilename" Grid.Column="1" Grid.Row="1" Text="" TextWrapping="Wrap" FontWeight="Bold" HorizontalAlignment="Left" />
            <TextBlock Grid.Column="0" Grid.Row="2" Margin="0 0 4 0" Text="Width:" HorizontalAlignment="Right" />
            <TextBlock x:Name="ElementWidth" Grid.Column="1" Grid.Row="2" Text="" FontWeight="Bold" HorizontalAlignment="Left" />
            <TextBlock Grid.Column="0" Grid.Row="3" Margin="0 0 4 0" Text="Height:" HorizontalAlignment="Right" />
            <TextBlock x:Name="ElementHeight" Grid.Column="1" Grid.Row="3" Text="" FontWeight="Bold" HorizontalAlignment="Left" />

            <RadioButton x:Name="ElementScaleRadio" Grid.Column="0" Grid.Row="6" Grid.ColumnSpan="2" VerticalAlignment="Bottom" Margin="8 0 0 4" GroupName="imageViewer" Content="Scale by %" Checked="ElementRadio_Click" />
            <Border Grid.Column="0" Grid.Row="7" Grid.ColumnSpan="2" Grid.RowSpan="3" Margin="6 0 4 0" BorderBrush="#aaaaaa" BorderThickness="1" CornerRadius="4" Background="#f0f0f0" />
            <TextBlock Grid.Column="0" Grid.Row="7" Margin="0 0 4 0" Text="Scale X:" VerticalAlignment="Center" HorizontalAlignment="Right" />
            <TextBlock x:Name="ElementScaleXLabel" Grid.Column="1" Grid.Row="7" Foreground="#444444" HorizontalAlignment="Center" VerticalAlignment="Bottom" />
            <Slider x:Name="ElementScaleX" Grid.Column="1" Grid.Row="7" VerticalAlignment="Center" Margin="0 0 10 0" Minimum="1" Maximum="200" SmallChange="1" />
            <TextBlock Grid.Column="0" Grid.Row="8" Margin="0 0 4 0" Text="Scale Y:" VerticalAlignment="Center" HorizontalAlignment="Right" />
            <TextBlock x:Name="ElementScaleYLabel" Grid.Column="1" Grid.Row="8" Foreground="#444444" HorizontalAlignment="Center" VerticalAlignment="Bottom" />
            <Slider x:Name="ElementScaleY" Grid.Column="1" Grid.Row="8" VerticalAlignment="Center" Margin="0 0 10 0" Minimum="1" Maximum="200" SmallChange="1" />
            <CheckBox x:Name="ElementLock" Grid.Column="1" Grid.Row="9" VerticalAlignment="Bottom" Margin="0 0 0 8" Content="Lock Scale" IsChecked="True" />

            <RadioButton x:Name="ElementPixelSizeRadio" Grid.Column="0" Grid.Row="10" Grid.ColumnSpan="2" VerticalAlignment="Bottom" Margin="8 0 0 4" GroupName="imageViewer" Content="Pixel Size" Checked="ElementRadio_Click" />
            <Border Grid.Column="0" Grid.Row="11" Grid.ColumnSpan="2" Grid.RowSpan="2" Margin="6 0 4 0" BorderBrush="#aaaaaa" BorderThickness="1" CornerRadius="4" Background="#f0f0f0" />
            <TextBlock Grid.Column="0" Grid.Row="11" Margin="0 0 4 0" Text="Width:" VerticalAlignment="Center" HorizontalAlignment="Right" />
            <liquid:NumericUpDown x:Name="ElementScaledSizeX" Grid.Column="1" Grid.Row="11" Width="70" HorizontalAlignment="Left" Margin="0 8 8 4" Height="26" ValueChanged="ElementScaledSize_ValueChanged" />
            <TextBlock Grid.Column="0" Grid.Row="12" Margin="0 0 4 0" Text="Height:" VerticalAlignment="Center" HorizontalAlignment="Right" />
            <liquid:NumericUpDown x:Name="ElementScaledSizeY" Grid.Column="1" Grid.Row="12" Width="70" HorizontalAlignment="Left" Margin="0 4 8 8" Height="26" ValueChanged="ElementScaledSize_ValueChanged" />
        </Grid>
    </Grid>
</UserControl>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using Liquid;

namespace RichTextBoxImageEdit
{
    public partial class ImageViewer : UserControl
    {
        private string _imageURL = string.Empty;
        private Image _image;
        private Size? _buildSize = null;
        private Size _originalSize = new Size();
        private bool _loaded = false;
        private string _targetPath = string.Empty;

        #region Public Properties

        public Dialog ParentDialog { get { return (Dialog)Parent; } }

        public string ImageURL
        {
            get { return _imageURL; }
        }

        public double ImageWidth
        {
            get { return Math.Round(_image.ActualWidth); }
        }

        public double ImageHeight
        {
            get { return Math.Round(_image.ActualHeight); }
        }

        public byte[] BitmapData { get; set; }

        public string Filename
        {
            get { return ElementFilename.Text; }
        }

        public bool ScaleByPercent
        {
            get { return ElementScaleRadio.IsChecked.Value; }
        }

        public double ScaleX
        {
            get { return ElementScaleX.Value; }
        }

        public double ScaleY
        {
            get { return ElementScaleY.Value; }
        }

        public bool ShowAlt { get; set; }

        #endregion

        public ImageViewer()
        {
            InitializeComponent();

            ElementScaleX.ValueChanged += new RoutedPropertyChangedEventHandler<double>(Scale_ValueChanged);
            ElementScaleY.ValueChanged += new RoutedPropertyChangedEventHandler<double>(Scale_ValueChanged);

            ShowAlt = true;
        }

        public void Build(string imageURL, string filename, Size? size)
        {
            SetEnabledState(false);

            _imageURL = imageURL;
            _buildSize = size;

            string[] split = _imageURL.Split('/');
            filename = split[split.Length - 1];
            string targetPath = imageURL.Replace(filename, "");

            _image = new Image();
            _image.Source = new BitmapImage(new Uri(_imageURL, UriKind.Relative));

            _image.Stretch = Stretch.Fill;
            _image.HorizontalAlignment = HorizontalAlignment.Center;
            _image.VerticalAlignment = VerticalAlignment.Center;
            _image.SizeChanged += new SizeChangedEventHandler(_image_SizeChanged);
            _image.CacheMode = new BitmapCache();

            ElementViewer.Content = _image;

            if (filename.Length > 0)
            {
                ElementFilename.Text = filename;
            }
            else if (imageURL.Length > 0)
            {
                split = _imageURL.Split('/');
                ElementFilename.Text = split[split.Length - 1];
            }

            _loaded = false;

            ElementScaleRadio.IsChecked = size == null;
            ElementPixelSizeRadio.IsChecked = size != null;
        }

        private void SetEnabledState(bool isEnabled)
        {
            if (!isEnabled)
            {
                ElementScaleRadio.IsEnabled = false;
                ElementScaleX.IsEnabled = false;
                ElementScaleY.IsEnabled = false;
                ElementLock.IsEnabled = false;

                ElementPixelSizeRadio.IsEnabled = false;
                ElementScaledSizeX.IsEnabled = false;
                ElementScaledSizeY.IsEnabled = false;
                ParentDialog.DisableAllButtons();
            }
            else
            {
                ElementScaleRadio.IsEnabled = true;
                ElementPixelSizeRadio.IsEnabled = true;

                ElementScaleX.IsEnabled = ElementScaleRadio.IsChecked.Value;
                ElementScaleY.IsEnabled = ElementScaleRadio.IsChecked.Value;
                ElementLock.IsEnabled = ElementScaleRadio.IsChecked.Value;

                ElementScaledSizeX.IsEnabled = ElementPixelSizeRadio.IsChecked.Value;
                ElementScaledSizeY.IsEnabled = ElementPixelSizeRadio.IsChecked.Value;

                ParentDialog.EnableAllButtons();
            }
        }

        #region Event Handling

        private void _image_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (!_loaded && e.NewSize.Height > 0 && e.NewSize.Width > 0)
            {
                SetEnabledState(true);
                _originalSize = new Size(_image.ActualWidth, _image.ActualHeight);

                ElementWidth.Text = _originalSize.Width.ToString() + "px";
                ElementHeight.Text = _originalSize.Height.ToString() + "px";

                if (_buildSize != null)
                {
                    ElementScaleX.Value = ((_buildSize.Value.Width / _image.ActualWidth) * 100);
                    ElementScaleY.Value = ((_buildSize.Value.Height / _image.ActualHeight) * 100);
                    _image.Width = Math.Round(_originalSize.Width * (ElementScaleX.Value * 0.01d));
                    _image.Height = Math.Round(_originalSize.Height * (ElementScaleY.Value * 0.01d));
                }
                else
                {
                    ElementScaleX.Value = 100;
                    ElementScaleY.Value = 100;

                    _image.Width = _originalSize.Width;
                    _image.Height = _originalSize.Height;
                }

                ElementScaledSizeX.Value = (int)Math.Round(_originalSize.Width * (ElementScaleX.Value * 0.01d));
                ElementScaledSizeY.Value = (int)Math.Round(_originalSize.Height * (ElementScaleY.Value * 0.01d));

                ParentDialog.GetButton("ok").IsEnabled = true;
                _loaded = true;
            }
        }

        private void Scale_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            ToolTipService.SetToolTip(ElementScaleX, Math.Round(ElementScaleX.Value));
            ToolTipService.SetToolTip(ElementScaleY, Math.Round(ElementScaleY.Value));

            ElementScaleXLabel.Text = Math.Round(ElementScaleX.Value).ToString() + "%";
            ElementScaleYLabel.Text = Math.Round(ElementScaleY.Value).ToString() + "%";
            ElementScaledSizeX.Value = (int)Math.Round(_originalSize.Width * (ElementScaleX.Value * 0.01d));
            ElementScaledSizeY.Value = (int)Math.Round(_originalSize.Height * (ElementScaleY.Value * 0.01d));

            if (ElementLock.IsChecked.Value)
            {
                if (sender == ElementScaleX)
                {
                    ElementScaleY.Value = ElementScaleX.Value;
                }
                if (sender == ElementScaleY)
                {
                    ElementScaleX.Value = ElementScaleY.Value;
                }
            }
        }

        private void ElementRadio_Click(object sender, RoutedEventArgs e)
        {
            if (_loaded)
            {
                ElementScaleX.IsEnabled = ElementScaleRadio.IsChecked.Value;
                ElementScaleY.IsEnabled = ElementScaleRadio.IsChecked.Value;
                ElementLock.IsEnabled = ElementScaleRadio.IsChecked.Value;

                ElementScaledSizeX.IsEnabled = ElementPixelSizeRadio.IsChecked.Value;
                ElementScaledSizeY.IsEnabled = ElementPixelSizeRadio.IsChecked.Value;
            }
        }

        private void ElementScaledSize_ValueChanged(object sender, EventArgs e)
        {
            _image.Width = ElementScaledSizeX.Value;
            _image.Height = ElementScaledSizeY.Value;
        }

        #endregion
    }
}


This is the dialog will be displayed when the image is double-clicked:

The Image Resize Dialog

Our Main Test Application

Here we have the main test application.  Note in the C# what we are doing in the ObjectDoubleClick event.  It is this event that we use to setup the Image Preview dialog.

<UserControl x:Class="RichTextBoxImageEdit.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:liquidRichText="clr-namespace:Liquid;assembly=Liquid.RichText"
    xmlns:liquidPopup="clr-namespace:Liquid;assembly=Liquid.Popup"
    xmlns:imageEdit="clr-namespace:RichTextBoxImageEdit"
    Width="640" Height="480">
  <Grid x:Name="LayoutRoot">
    <liquidRichText:RichTextBox x:Name="richTextBox" Width="380" Height="300" Margin="4" HorizontalAlignment="Left" VerticalAlignment="Top" EnableObjectSelection="True" />
    <liquidPopup:Dialog x:Name="resizeDialog" Width="610" Height="410" Title="Image Resize" Closed="resizeDialog_Closed">
        <imageEdit:ImageViewer x:Name="resizer" />
    </liquidPopup:Dialog>
  </Grid>
</UserControl>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using Liquid;

namespace RichTextBoxImageEdit
{
    public partial class MainPage : UserControl
    {
        private Image _currentImage = null;

        public MainPage()
        {
            InitializeComponent();

            richTextBox.HTML = "<p>Double-click the image to resize!</p><img src=\"images/Lake.jpg\" />";
            richTextBox.ObjectDoubleClick += new RichTextBoxEventHandler(richTextBox_ObjectDoubleClick);
        }

        private void richTextBox_ObjectDoubleClick(object sender, RichTextBoxEventArgs e)
        {
            List<UIElement> selected = richTextBox.GetSelectedObjects();

            if (selected.Count > 0 && selected[0] is Image)
            {
                _currentImage = (Image)selected[0];
                BitmapImage imageSource = (BitmapImage)_currentImage.Source;

                resizer.Build(imageSource.UriSource.ToString(), imageSource.UriSource.ToString(), new Size(_currentImage.ActualWidth, _currentImage.ActualHeight));
                
                resizeDialog.ShowAsModal();
            }
        }

        private void resizeDialog_Closed(object sender, DialogEventArgs e)
        {
            if (resizeDialog.Result == DialogButtons.OK)
            {
                richTextBox.ResizeImage(_currentImage, new Size(resizer.ImageWidth, resizer.ImageHeight));
            }
        }

        private void save_Click(object sender, RoutedEventArgs e)
        {
            string html = richTextBox.Save(Format.HTML, RichTextSaveOptions.None);
        }
    }
}


There is plenty of scope for improvement here.  In our dialog we simply allow a % to be applied to the X/Y axis or an actual Pixel Size.

Rate this: 

1 Star 2 Star 3 Star 4 Star 5 Star
12 Ratings / 3.2 Average

Tweets

Silverlight Controls

  • Rich TextBox

    Create and edit rich content with this slick and expandable Rich TextBox...

  • TreeView

    This easy to use TreeView comes with drag and drop, sorting, searching and much more...

  • Context Menu

    You too can have cool popup context menus in your Silverlight applications...

  • Resizable Dialog

    Draggable and resizable popup dialogs are what serious Silverlight developers need...

  • Spell Checker

    Real-time spell checking in Silverlight? We did it first here...