#723 – Turning Off All Caps Menus in Visual Studio 2012

One of the changes in Visual Studio 2012 was to render the main menus in all caps.  This was done to better match the new Metro (Windows Store) style of user interface, used across other Microsoft products.  (E.g. Office 2013 or the Bing web site).

747-001

However, many people have argued that using all caps make the user interface less readable and constitutes bad typography.

If you prefer using upper and lowercase in the main menu, you can turn off the all caps by adding a value in the registry.

In the key HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\General, create a DWORD value named SuppressUppercaseConversion and set its value to 1.

You’ll now get upper and lowercase in the menus.

747-002

#722 – Get a Free Copy of Visual Studio 2012

You can start developing WPF applications by using the Visual Studio 2012 Express edition listed below.  This edition is free and allows you to create WPF applications for the desktop.

  • Visual Studio Express 2012 for Windows Desktop

Additionally, you can get a free copy of Visual Studio Team Foundation Server Express 2012, which allows up to five developers to do source code control, work item tracking, and build automation.

#721 – A Tool for Viewing the Clipboard

Here’s a handy free tool for viewing the contents of the clipboard – Clipboard Master, by Jumping Bytes Software.

Once installed, you can press the Windows Key + V combination and a Clipboard Master window will pop up, showing you the full contents of the clipboard and allowing you to select an item to paste.  Notice that if there are multiple items on the clipboard, in different formats, you can choose which item to paste.

721-001

#720 – Discovering What Kind of Data Is on the Clipboard

You can use one of several static methods in the Clipboard class to find out what type of data is currently on the Windows clipboard.

There are several methods that check for a specific format (ContainsAudioContainsFileDropListContainsImage, and ContainsText).  You can also use the ContainsData method to check for a specific format.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sbCB = new StringBuilder();

            // Check for some specific formats
            if (Clipboard.ContainsAudio())
                sbCB.Append("Audio ");

            if (Clipboard.ContainsFileDropList())
                sbCB.Append("FileDropList ");

            if (Clipboard.ContainsImage())
                sbCB.Append("Image ");

            if (Clipboard.ContainsText())
                sbCB.Append("Text ");

            // Can also check for specific formats
            // (See System.Windows.DataFormats for full list)
            if (Clipboard.ContainsData(DataFormats.CommaSeparatedValue))
                sbCB.Append("CommaSeparatedValue ");

            if (Clipboard.ContainsData(DataFormats.EnhancedMetafile))
                sbCB.Append("EnhancedMetafile ");

            lblInfo.Content = "Clipboard contains: " + sbCB.ToString();
        }

720-001
720-002

#719 – ASCII Art Generator

Here’s a WPF-based ASCII Art generator that I wrote.  Merry Christmas!

The GUI just consists of a button for selecting a file and a label indicating the file that was selected.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Content="{Binding InputFile}"
               HorizontalAlignment="Left" VerticalAlignment="Center"
               Margin="10"/>
        <Button Content="Select File" Grid.Column="1"
                HorizontalAlignment="Left" VerticalAlignment="Center"
                Padding="10,5" Margin="10"
                Click="btnSelectFile_Click"/>
    </Grid>

In the code-behind, we generate an output file name and load the input file into a Bitmap before calling the main ASCII Art generation method.

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            inputFile = "Select an image file to use for ASCII Art";
        }

        private string inputFile;
        public string InputFile
        {
            get { return inputFile; }
            set
            {
                if (value != inputFile)
                {
                    inputFile = value;
                    RaisePropertyChanged("InputFile");
                }
            }
        }

        async private void btnSelectFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Image Files (*.jpg, *.png)|*.jpg;*.png;";
            ofd.Title = "Select an image file to convert";

            try
            {
                bool? bResult = ofd.ShowDialog();
                if (bResult.HasValue && (bool)bResult)
                {
                    InputFile = ofd.FileName;
                    await Task.Run(() => DoGenerate(InputFile));
                }
            }
            catch (Exception xx)
            {
                MessageBox.Show(string.Format("Fatal Error: {0}", xx.ToString()), "Fatal Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void DoGenerate(string inputFile)
        {
            int outputWidth = 100;

            FileInfo fi = new FileInfo(inputFile);
            if (!fi.Exists)
                throw new Exception(string.Format("File {0} not found", inputFile));
            string outputFile = Path.Combine(fi.DirectoryName, Path.GetFileNameWithoutExtension(inputFile) + ".txt");

            Bitmap bmInput = new Bitmap(inputFile);

            if (outputWidth > bmInput.Width)
                throw new Exception("Output width must be <= pixel width of image");

            // Generate the ASCII art
            AscArt.GenerateAsciiArt(bmInput, outputFile, outputWidth);

            // This will fire up default app for .txt files
            Process.Start(outputFile);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }

Finally, here is the code for the class that generates the ASCII art.

    public static class AscArt
    {
        // Typical width/height for ASCII characters
        private const double FontAspectRatio = 0.6;

        // Available character set, ordered by decreasing intensity (brightness)
        private const string OutputCharSet = "@%#*+=-:. ";

        // Alternate char set uses more chars, but looks less realistic
        private const string OutputCharSetAlternate = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. ";

        public static void GenerateAsciiArt(Bitmap bmInput, string outputFile, int outputWidth)
        {
            // pixelChunkWidth/pixelChunkHeight - size of a chunk of pixels that will
            // map to 1 character.  These are doubles to avoid progressive rounding
            // error.
            double pixelChunkWidth = (double)bmInput.Width / (double)outputWidth;
            double pixelChunkHeight = pixelChunkWidth / FontAspectRatio;

            // Calculate output height to capture entire image
            int outputHeight = (int)Math.Round((double)bmInput.Height / pixelChunkHeight);

            // Generate output image, row by row
            double pixelOffSetTop = 0.0;
            StringBuilder sbOutput = new StringBuilder();

            for (int row = 1; row <= outputHeight; row++)
            {
                double pixelOffSetLeft = 0.0;

                for (int col = 1; col <= outputWidth; col++)
                {
                    // Calculate brightness for this set of pixels by averaging
                    // brightness across all pixels in this pixel chunk
                    double brightSum = 0.0;
                    int pixelCount = 0;
                    for (int pixelLeftInd = 0; pixelLeftInd < (int)pixelChunkWidth; pixelLeftInd++)
                        for (int pixelTopInd = 0; pixelTopInd < (int)pixelChunkHeight; pixelTopInd++)
                        {
                            // Each call to GetBrightness returns value between 0.0 and 1.0
                            int x = (int)pixelOffSetLeft + pixelLeftInd;
                            int y = (int)pixelOffSetTop + pixelTopInd;
                            if ((x < bmInput.Width) && (y < bmInput.Height))
                            {
                                brightSum += bmInput.GetPixel(x, y).GetBrightness();
                                pixelCount++;
                            }
                        }

                    // Average brightness for this entire pixel chunk, between 0.0 and 1.0
                    double pixelChunkBrightness = brightSum / pixelCount;

                    // Target character is just relative position in ordered set of output characters
                    int outputIndex = (int)Math.Floor(pixelChunkBrightness * OutputCharSet.Length);
                    if (outputIndex == OutputCharSet.Length)
                        outputIndex--;

                    char targetChar = OutputCharSet[outputIndex];

                    sbOutput.Append(targetChar);

                    pixelOffSetLeft += pixelChunkWidth;
                }
                sbOutput.AppendLine();
                pixelOffSetTop += pixelChunkHeight;
            }

            // Dump output string to file
            File.WriteAllText(outputFile, sbOutput.ToString());
        }
    }

719-001

 

Full solution available here.

#718 – Copying Text To and From the Clipboard

You can copy data to or from the Windows clipboard using static methods in the System.Windows.Clipboard class.

Here’s an example that copies text from a TextBox onto the clipboard and pastes text from the clipboard into a Label.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <TextBox Name="txtFrom" Text="Twas the Night Before Christmas.." Margin="10"/>
        <Button Grid.Column="1" Content="Copy"
                HorizontalAlignment="Left" Padding="10,5" Margin="10"
                Click="btnCopy_Click"/>

        <Label Name="lblTo" Grid.Row="1" Content="Paste something here"
               Margin="10"/>
        <Button Grid.Row="1" Grid.Column="1" Content="Paste"
                VerticalAlignment="Top" HorizontalAlignment="Left"
                Padding="10,5" Margin="10"
                Click="btnPaste_Click"/>
    </Grid>

The Click handlers use the SetText and GetText methods of the Clipboard class to interact with the clipboard.  The SetText method copies data to the clipboard.  The GetText method pastes data from the clipboard.

        private void btnCopy_Click(object sender, RoutedEventArgs e)
        {
            Clipboard.SetText(txtFrom.Text);
        }

        private void btnPaste_Click(object sender, RoutedEventArgs e)
        {
            lblTo.Content = Clipboard.GetText();
        }

718-001

718-002

718-003

718-004

718-005

#717 – Drag-and-Drop with Touch on Windows 7

You can implement drag-and-drop on a touch-based system in a similar way to how you implement drag-and-drop using the mouse.

You start by defining a handler for the TouchDown event of the control that serves as a drag source.  You then define a handler for the Drop event of the control that is the drop target.

    <StackPanel>
        <Label Content="Benjamin Disraeli"
               Background="AliceBlue" Margin="15" Padding="30,20" HorizontalAlignment="Center"
               TouchDown="Label_TouchDown"/>
        <Label Content="Drag to here"
               Background="Bisque" Margin="15" Padding="30,20" HorizontalAlignment="Center"
               AllowDrop="True" Drop="Label_Drop"/>
    </StackPanel>

In the code-behind, you call the DoDragDrop method to initiate drag-and-drop.

        // Drag source
        private void Label_TouchDown(object sender, TouchEventArgs e)
        {
            Label l = e.Source as Label;
            DragDrop.DoDragDrop(l, l.Content + " was Dragged!", DragDropEffects.Copy);
        }

        // Drag target
        private void Label_Drop(object sender, DragEventArgs e)
        {
            string draggedText = (string)e.Data.GetData(DataFormats.StringFormat);
            Label l = e.Source as Label;
            l.Content = draggedText;
        }

You can now touch and hold your finger down to drag.

717-001

717-002

#716 – Using a Border As a Visual Indication That a Control Can Be Dragged

You can use the Thumb control to allow dragging a control around on a parent Canvas.  To make it a little more obvious to the user that the control can be dragged, you can set up a Border around the control that only shows up when the user moves the mouse over the control.

    <Window.Resources>
        <Style x:Key="BorderVisibleOnMouse" TargetType="Border">
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Style.Triggers>
                <Trigger Property="Border.IsMouseOver" Value="True">
                    <Setter Property="BorderBrush" Value="LightBlue"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <Canvas>
        <Thumb Canvas.Left="100" Canvas.Top="60" DragDelta="Thumb_DragDelta">
            <Thumb.Template>
                <ControlTemplate>
                    <Border Style="{StaticResource ResourceKey=BorderVisibleOnMouse}">
                        <Label Content="Elvis Drafted!"/>
                    </Border>
                </ControlTemplate>
            </Thumb.Template>
        </Thumb>
        <Thumb Canvas.Left="30" Canvas.Top="180" DragDelta="Thumb_DragDelta">
            <Thumb.Template>
                <ControlTemplate>
                    <Border Style="{StaticResource ResourceKey=BorderVisibleOnMouse}">
                        <Label Content="Richard the Lion-Hearted Captured!"/>
                    </Border>
                </ControlTemplate>
            </Thumb.Template>
        </Thumb>
    </Canvas>

716-001
716-002
716-003

#715 – Using the Thumb Control to Drag Objects on a Canvas

You can use the Thumb control for simple dragging of objects on a Canvas.  You set the Template of the Thumb control to contain the actual element to be dragged and then handle the thumb’s DragDelta event.

Below is a Canvas containing three controls, each wrapped in a Thumb and therefore draggable.

    <Canvas>
        <Thumb Canvas.Left="10" Canvas.Top="20" Canvas.ZIndex="99"  DragDelta="Thumb_DragDelta">
            <Thumb.Template>
                <ControlTemplate>
                    <Image Width="60" Height="60" Source="Crown.jpg"/>
                </ControlTemplate>
            </Thumb.Template>
        </Thumb>
        <Thumb Canvas.Left="100" Canvas.Top="60" DragDelta="Thumb_DragDelta">
            <Thumb.Template>
                <ControlTemplate>
                    <Image Width="80" Height="100" Source="HenryII.jpg"/>
                </ControlTemplate>
            </Thumb.Template>
        </Thumb>
        <Thumb Canvas.Left="30" Canvas.Top="180" DragDelta="Thumb_DragDelta">
            <Thumb.Template>
                <ControlTemplate>
                    <Label Content="Westminster, 19-Dec-1154"/>
                </ControlTemplate>
            </Thumb.Template>
        </Thumb>
    </Canvas>

In the event handler for each of the Thumb controls, we simply adjust the thumb’s position on the Canvas.

        private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            UIElement thumb = e.Source as UIElement;

            Canvas.SetLeft(thumb, Canvas.GetLeft(thumb) + e.HorizontalChange);
            Canvas.SetTop(thumb, Canvas.GetTop(thumb) + e.VerticalChange);
        }

715-001
715-002

#714 – Setting the Cursor to Render Some Text While Dragging

You can use the GiveFeedback to change the cursor during a drag-and-drop operation.  You can set the cursor to be some text by rendering a visual element to a bitmap and then converting that bitmap to a cursor.

Here’s a helper class containing a method that converts some text to a cursor.

    public class CursorHelper
    {
        private static class NativeMethods
        {
            public struct IconInfo
            {
                public bool fIcon;
                public int xHotspot;
                public int yHotspot;
                public IntPtr hbmMask;
                public IntPtr hbmColor;
            }

            [DllImport("user32.dll")]
            public static extern SafeIconHandle CreateIconIndirect(ref IconInfo icon);

            [DllImport("user32.dll")]
            public static extern bool DestroyIcon(IntPtr hIcon);

            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
        }

        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
        private class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            public SafeIconHandle()
                : base(true)
            {
            }

            override protected bool ReleaseHandle()
            {
                return NativeMethods.DestroyIcon(handle);
            }
        }

        private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp)
        {
            var iconInfo = new NativeMethods.IconInfo();
            NativeMethods.GetIconInfo(bmp.GetHicon(), ref iconInfo);

            iconInfo.xHotspot = 0;
            iconInfo.yHotspot = 0;
            iconInfo.fIcon = false;

            SafeIconHandle cursorHandle = NativeMethods.CreateIconIndirect(ref iconInfo);
            return CursorInteropHelper.Create(cursorHandle);
        }

        public static Cursor CreateCursor(string cursorText)
        {
            // Text to render
            FormattedText fmtText = new FormattedText(cursorText,
                    new CultureInfo("en-us"),
                    FlowDirection.LeftToRight,
                    new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Normal, new FontStretch()),
                    12.0,  // FontSize
                    Brushes.Black);

            // The Visual to use as the source of the RenderTargetBitmap.
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();
            drawingContext.DrawText(fmtText, new Point());
            drawingContext.Close();

            // The BitmapSource that is rendered with a Visual.
            RenderTargetBitmap rtb = new RenderTargetBitmap(
                (int)drawingVisual.ContentBounds.Width,
                (int)drawingVisual.ContentBounds.Height,
                96,   // dpiX
                96,   // dpiY
                PixelFormats.Pbgra32);
            rtb.Render(drawingVisual);

            // Encoding the RenderBitmapTarget into a bitmap (as PNG)
            PngBitmapEncoder encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(rtb));

            using (var ms = new MemoryStream())
            {
                encoder.Save(ms);
                using (var bmp = new System.Drawing.Bitmap(ms))
                {
                    return InternalCreateCursor(bmp);
                }
            }
        }
    }

We can test this code by setting the cursor to some text when we drag a Label.

    <StackPanel>
        <Label Content="Mayflower" Background="AliceBlue" 
               HorizontalAlignment="Center" Margin="15" Padding="20,5"
               MouseLeftButtonDown="Label_MouseLeftButtonDown"
               GiveFeedback="Label_GiveFeedback"/>
        <Label Content="Drag to here" Background="SpringGreen" 
               HorizontalAlignment="Center" Margin="15"
               Drop="Label_Drop"/>
    </StackPanel>

Here’s the code for the drag-and-drop operation.

        private void Label_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DataObject data = new DataObject(DataFormats.Text, ((Label)e.Source).Content);

            DragDrop.DoDragDrop((DependencyObject)e.Source, data, DragDropEffects.Copy);
        }

        private void Label_Drop(object sender, DragEventArgs e)
        {
            ((Label)e.Source).Content = (string)e.Data.GetData(DataFormats.Text);
        }

        private Cursor customCursor = null;

        private void Label_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            if (e.Effects == DragDropEffects.Copy)
            {
                if (customCursor == null)
                    customCursor = CursorHelper.CreateCursor("Mayflower - 18 Dec 1620");

                if (customCursor != null)
                {
                    e.UseDefaultCursors = false;
                    Mouse.SetCursor(customCursor);
                }
            }
            else
                e.UseDefaultCursors = true;

            e.Handled = true;
        }

714-001