#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

Advertisements

#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