Find patterns within Pi in C#

[pi]

March 14 is known as Pi Day because its numeric representation 3/14 includes the first three digits of Pi: 3.14. (At least in the United States. In Europe where they usually write dates month first, Pi Day is July 22 because 22/7 is also a good approximation of Pi.)

Because you can find 3/14 in the digits of Pi, you might wonder whether you can find other patterns of digits in Pi. This program searches the first 100 thousand digits of Pi to find dates or other patterns that you enter.

The program includes the file Pi.txt. (I got this file from the web site Digits of Pi, where you can download 10, 50, 1 hundred, 1 thousand, 10 thousand, 100 thousand, or 1 million digits of Pi.)

At design time I opened Solution Explorer, right-clicked the project, opened the Add menu item, selected Existing Item, and added the file to the project. I then set the file’s “Copy to Output Directory” property to “Copy if newer.” Now when the program runs, the file is copied into the executable directory if it isn’t already there.

When the program starts, it uses the following code to load the file.

// The digits of pi.
private string Pi;

// Load the digits of pi.
private void Form1_Load(object sender, EventArgs e)
{
    Pi = File.ReadAllText("Pi.txt");
    rchPi.Text = Pi;
    rchPi.Select(0, 0);
    lblPosition.Text = "";
}

This code defines variable Pi at the class level. The form’s Load event handler uses System.IO.File.ReadAllText to read the file into the string Pi.

The code then displays the string Pi in the RichTextBox named rchPi.

When you enter a pattern in the text box and click Search, the program executes the following code.

// Search for a pattern.
private void btnSearch_Click(object sender, EventArgs e)
{
    // Get the pattern.
    string pattern = txtPattern.Text;

    // Remove all non-digits.
    Regex reg_exp = new Regex("[^0-9]");
    pattern = reg_exp.Replace(pattern, "");

    // Search for the pattern.
    int position = Pi.IndexOf(pattern);

    // Display the result.
    rchPi.Text = Pi;
    if (position < 0)
        lblPosition.Text = pattern + " was not found";
    else
    {
        lblPosition.Text = pattern +
            " found at digit " + position.ToString();
        rchPi.Select(position, pattern.Length);
        rchPi.SelectionBackColor = Color.Yellow;
        rchPi.SelectionColor = Color.Red;
        rchPi.ScrollToCaret();
    }
}

This code gets the pattern that you entered. It then creates a Regex object that searches for non-digits and uses that pattern to replace non-digits with empty strings, thus removing the non-digits from the pattern.

Next the code searches Pi for the pattern. If the pattern does not appear, the code says so. If the pattern is contained in the string Pi, the program highlights it in the RichTextBox.

In fact, it is not known whether Pi contains every finite pattern of digits although most mathematicians believe it does. There are certainly some interesting patterns in there. For example, use this program to search for the pattern 999999 or 12345. This program only searches the first 100 thousand digits of Pi, however, so there are lots of patterns that it cannot find.

Some may be tempted to think there's some sort of mystical significance to the fact that Pi may contain every possible pattern. For example, if Pi really does contain all possible finite sequences of digits, then somewhere in there is the ASCII encoding of all of Shakespeare's works including all of his lost works. In that case, you could imagine that some divine being has hidden a message for you in Pi.

Of course the digits of Pi would also include ASCII encodings of every other conceivable piece of gibberish. They would include, "Go forth and bring peace unto the world," but they would also include, "Go forth and s#*9n GR&HH @F5& s-x r!KWY."

So use this program to look for your birthday, but don't it all too seriously.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, mathematics, strings | Tagged , , , , , , , , , , , , , | 1 Comment

Puzzle: The 40 pound stone

[puzzle]

This is a variation of a puzzle given on Car Talk. It’s similar to some of the puzzles in my book Interview Puzzles Dissected.

A farmer uses a double-pan balance and a 40 pound stone to measure 40 pound weights: grain, flour, turnips, whatever. One day he loans his weighing stone to a neighbor who accidentally breaks it into four not-necessarily-equal-sized pieces.

After sulking for a few days, he tells his neighbor, “I have to thank you. With the four pieces I can now weigh any integer weight between 1 and 40 pounds!”

What are the weights of the pieces?


[puzzle]

This puzzle is similar to the pan balance puzzles described in my book, Interview Puzzles Dissected. It explains how these puzzles work, describes variations on the puzzles, and tells you what the “trick” is for solving other similar puzzles.

The book’s sample puzzles page describes and solves three different kinds of puzzles.

(I’ll post the solution to this puzzle in a day or two.)


Follow me on Twitter   RSS feed   Donate




Posted in algorithms, books, games, puzzles | Tagged , , , , , , , , | Leave a comment

Make the basis for a card game in C#

[card game]

The goal of this example is to provide some support for building a card game. It shows how to make a class to represent cards and to to tell what card is displayed in a PictureBox. It’s actually relatively straightforward.


The following code shows the Card class.

public class Card
{
    public int Rank, Suit;
    public Bitmap Picture;

    public Card(int rank, int suit, Bitmap picture)
    {
        Rank = rank;
        Suit = suit;
        Picture = picture;
    }
}

The class first defines the Rank and Suit properties. For this example I’ve made them numeric. Rank will be between 0 (Ace) and 12 (King).

Suit will be 0 and 4 and will represent hearts, diamonds, clubs, spades, and other. The suits are in that order because that’s the order in which they appear in the image file cards.png. You could rearrange them if you like.

The last Suit value holds the card backs and other miscellaneous images that might be used by a card game. The cards.png image doesn’t include jokers, but this is where you would put them if you wanted them.

The following code shows the variables that the program uses to store card information.

// Basic deck information.
// The 5th suite is for the back, jokers, etc.
private const int NumSuits = 5;
private const int NumRanks = 13;
private int CardWidth, CardHeight;

// The suits in their order in the file.
private enum Suits
{
    Hearts,
    Diamonds,
    Clubs,
    Spades,
    Misc,
}

// PictureBoxes holding card images.
private PictureBox[,] Pics = null;

The values NumSuits and NumRanks hold the numbers of suits and ranks. The fields CardWidth and CardHeight will later hold the dimensions of the card images.

The Suits enumeration makes it easier to map indexes to suits.

The Pics array will hold PictureBox controls holding the cards.

When the program starts, the following Load event handler loads the card data.

// Load the cards.
private void Form1_Load(object sender, EventArgs e)
{
    // Load the card images.
    LoadCardImages();

    // Arrange the card PictureBoxes.
    ArrangeCards();
}

This code simply calls the LoadCardImages and ArrangeCards methods. The following code shows LoadCardImages.

// Load the card PictureBoxes.
private void LoadCardImages()
{
    CardWidth = Properties.Resources.cards.Width / NumRanks;
    CardHeight = Properties.Resources.cards.Height / NumSuits;
    int x0 = 0;
    int y0 = 0;
    int dx = CardWidth;
    int dy = CardHeight;
    Pics = new PictureBox[NumRanks, NumSuits];
    int y = y0;
    for (int suit = 0; suit < NumSuits; suit++)
    {
        int x = x0;
        for (int rank = 0; rank < NumRanks; rank++)
        {
            Pics[rank, suit] = LoadCard(rank, suit, x, y);
            x += dx;
        }
        y += dy;
    }
}

The resource Properties.Resources.cards holds the image of all of the cards. This method uses it to get the cards’ widths and heights. It then allocates the Pics array and loops through the image to get the individual card images.

As it moves through the rows and columns of card images, the code keeps track of its position in the main image and calls the LoadCard method to load each of the cards.

The following code shows the LoadCard method.

// Load a single card from the deck.
private PictureBox LoadCard(int rank, int suit, int x, int y)
{
    // Get the image.
    PictureBox pic = new PictureBox();
    Bitmap bm = LoadCardImage(rank, suit, x, y);

    // Make the PictureBox.
    pic.Image = bm;
    pic.SizeMode = PictureBoxSizeMode.AutoSize;
    pic.BorderStyle = BorderStyle.Fixed3D;
    pic.Parent = panCards;
    pic.MouseEnter += pic_MouseEnter;
    pic.MouseLeave += pic_MouseLeave;

    // Give the PictureBox a Card object so
    // we can tell what card it is.
    pic.Tag = new Card(rank, suit, bm);

    return pic;
}

This method creates a new PictureBox to hold the card. Depending on what your card game is going to do, you may not want to create a PictureBox for each card. For example, you might want to just create Card objects to represent the cards. Then you can display them in PictureBoxes later. This example just loads the images and displays them in separate PictureBox controls so it’s not really a card game at all.

After it creates the PictureBox, the method calls LoadCardImage to load the image for the card. It then sets various PictureBox properties including its Image, SizeMode, and BorderStyle. It sets the Parent to the Panel control named panCards. That control has AutoScroll = True so it displays scroll bars if the PictureBox controls inside it don’t fit in its visible area.

Finally the method sets the PictureBox control’s Tag property equal to a Card object that holds the card’s information. Later the program can use the Tag object to see what card the PictureBox represents.

The following code shows the LoadCardImage method.

// Return the image for a card.
private Bitmap LoadCardImage(int rank, int suit, int x, int y)
{
    Bitmap bm = new Bitmap(CardWidth, CardHeight);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        Rectangle dest_rect =
            new Rectangle(0, 0, CardWidth, CardHeight);
        Rectangle src_rect =
            new Rectangle(x, y, CardWidth, CardHeight);
        gr.DrawImage(Properties.Resources.cards,
            dest_rect, src_rect, GraphicsUnit.Pixel);
    }

    return bm;
}

This method creates a Bitmap to hold the card’s image and makes an associated Graphics object. Next it makes a rectangle that fills the new bitmap.
It also makes rectangles that identifies the location where the image should be copied from the big bitmap containing all of the card images. Finally the code copies the card’s image from the big bitmap into the new bitmap and returns it.

The following code shows the ArrangeCards method.

// Arrange the card PictureBoxes.
private void ArrangeCards()
{
    // Display the deck.
    const int margin = 4;
    int y = margin;
    for (int suit = 0; suit < NumSuits; suit++)
    {
        int x = margin;
        for (int rank = 0; rank < NumRanks; rank++)
        {
            Pics[rank, suit].Location = new Point(x, y);
            x += Pics[0, 0].Width + margin;
        }
        y += Pics[0, 0].Height + margin;
    }
}

This method simply loops through the PictureBox controls in the Pics array and positions the controls in rows and columns within the Panel.

The final pieces of the program include the following event handlers, which execute when the mouse enters or leaves a PictureBox.

// Display the card's information.
private void pic_MouseEnter(object sender, EventArgs e)
{
    // Get the card information.
    PictureBox pic = sender as PictureBox;
    Card card = pic.Tag as Card;
    Suits suit = (Suits)card.Suit;
    int rank = card.Rank + 1;
    Text = rank.ToString() + " of " + suit.ToString();
}

// Clear the cardf information.
private void pic_MouseLeave(object sender, EventArgs e)
{
    Text = "howto_playing_cards";
}

The pic_MouseEnter event handler converts the sender object into the PictureBox that raised the event. It then gets the control's Tag property and converts it into a Card object. The event handler finishes by displaying the Card object's rank (plus 1) and suit in the form's title bar.

The pic_MouseLeave property simply resets the form's title bar so it displays the program's name instead of whatever card the mouse last passed over.

The Card class and the technique of storing Card objects in a PictureBox control's Tag property should help you get started making a card game.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in games, graphics, image processing, puzzles | Tagged , , , , , , , , , , , , | Leave a comment

Verify sizes of playing cards in C#


[playing cards]

Recently I wanted to use some playing cards in a program so I looked online for some nice images. I could have included 55 or so separate images (including jokers and backs), but I decided it would be easier to use a single image to hold images for all of the playing cards.

Surprisingly when I tried to display the playing cards, the images didn’t line up. The first few cards looked okay but then later cards lined up more and more badly until the last few didn’t fit at all.

[example]

If you look closely at the red outlines in the picture on the right, you’ll see that the Ace of hearts lines up nicely but the cards on the bottom and right edges of the picture do not sit well within their outlines.

The problem is that the image of the playing cards doesn’t give each card an integral size. I suspect what happened in these cases is that the image’s author made the playing cards at a handy size and then scaled the image of the deck to some other size that was convenient for posting. For example, the image shown here that doesn’t line up nicely was originally 994×447 pixels in size. (It’s included in the download so you can see it and you can find it on Wikimedia Commons.)

The width 994 divided by 13 is 76.46, so the cards don’t have integral widths. The program truncates the result to 76. As it moves to the right through the image of the deck, the missing 0.46 adds up until the final cards are pretty far out of alignment. (The same thing happens vertically.)

One solution (and the one I probably should have taken because it would have been easier) would be to use the float data type for the card dimensions. I decided that I wanted to use integer dimensions so the card images wouldn’t be scaled and they would be perfect.

Eventually I found an image online (at thehouseofcards.com) with dimensions 936×500. It has 13 columns and 5 rows of playing cards so each is exactly 72×100 pixels.

Anyway, I wrote this program to load an image containing playing cards and then draw lines to show how the cards line up.

When it starts, the program uses the following code to save the original image of the playing cards.

// The original image.
private Bitmap OriginalImage = null;

// Save the original image.
private void Form1_Load(object sender, EventArgs e)
{
    OriginalImage = picDeck.Image as Bitmap;
}

When you click the Outline button, the following code executes.

// Draw lines on the deck to show where the cards are.
private void btnOutline_Click(object sender, EventArgs e)
{
    int NumSuits = int.Parse(txtNumSuits.Text);
    int NumRanks = int.Parse(txtNumRanks.Text);

    Bitmap bm = new Bitmap(picDeck.Image);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        int wid = bm.Width / NumRanks;
        int hgt = bm.Height / NumSuits;
        for (int x = 0; x <= NumRanks; x++)
            gr.DrawLine(Pens.Blue, x * wid, 0, x * wid, bm.Height);
        for (int y = 0; y <= NumSuits; y++)
            gr.DrawLine(Pens.Blue, 0, y * hgt, bm.Width, y * hgt);
    }
    picDeck.Image = bm;
}

This code parses the number of suits and ranks that you entered in the form's text boxes. It then creates a new Bitmap that contains a copy of the original image, and then makes an associated Graphics object.

Next the code calculates the integral dimensions of the individual playing cards. It loops through the ranks drawing vertical lines between the cards and then loops through the suits drawing horizontal lines between the cards.

Finally the code displays the new image.

In my next post, I'll describe a program that uses this image to load the separate playing cards. It then displays them in a way that lets the program figure out which card is displayed where.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in games, graphics, image processing, puzzles | Tagged , , , , , , , , , , , | Leave a comment

Use System.Threading.Timer to make a countdown timer in C#

[example]

The post Make a countdown timer in C# uses a Timer control to count down the time until some deadline. This example does something similar but it uses a Timer object from the System.Threading namespace.

The basic idea is similar: use the timer to periodically see how long it is until the deadline and then display the time remaining. The first part is straightforward. Unfortunately this kind of timer’s periodic event does not occur in the UI thread so its code cannot directly update the form’s labels. Instead it must call some control’s Invoke method to execute some other method on the UI thread.

The following code executes when the program starts.

// The timer.
System.Threading.Timer TheTimer = null;

// Initialize information about the event.
private DateTime EventDate = new DateTime(2017, 4, 1);

private void Form1_Load(object sender, EventArgs e)
{
    // Make the timer start now and tick every 500 ms.
    TheTimer = new System.Threading.Timer(
        this.Tick, null, 0, 500);
}

This code declares two variables at the class level. First it declares a System.Threading.Timer object. It then creates a DateTime to hold the event date.

The form’s Load event handler creates the Timer object. The constructor’s parameters are:

  • this.Tick – The callback method that the Timer should invoke
  • null – An object to pass into the callback method
  • 0 – The amount of time the Timer should wait before its first call to the callback method
  • 500 – The number of milliseconds between calls to the callback method

The following code shows the Tick callback method.

// The timer ticked.
public void Tick(object info)
{
    this.Invoke((Action)this.UpdateCountdown);
}

In the earlier version of this program, the Timer control’s Tick event handler updates the program’s labels. As I mentioned above, this new Tick method isn’t running on the same thread that created the program’s user interface. That means it is not allowed to update the control’s in the user interface, in particular the labels.

To work around that, the code calls the form’s Invoke method, passing it the this.UpdateCountdown method. The (Action) in front of the method name converts the method into a delegate — a variable that contains the address of the method.

The Invoke method queues the call to this.UpdateCountdown so it will run on the UI thread. Because it runs on the UI thread, that method is allowed to update the form’s labels.

The following code shows the UpdateCountdown method.

// Update the countdown on the UI thread.
private void UpdateCountdown()
{
    TimeSpan remaining = EventDate - DateTime.Now;
    if (remaining.TotalSeconds < 1)
    {
        TheTimer.Dispose();
        this.WindowState = FormWindowState.Maximized;
        this.TopMost = true;

        foreach (Control ctl in this.Controls)
            ctl.Visible = (ctl == lblFinished);

        using (SoundPlayer player = new SoundPlayer(
            Properties.Resources.tada))
        {
            player.Play();
        }
    }
    else
    {
        lblDays.Text = remaining.Days + " days";
        lblHours.Text = remaining.Hours + " hours";
        lblMinutes.Text = remaining.Minutes + " minutes";
        lblSeconds.Text = remaining.Seconds + " seconds";
    }
}

This code subtracts the current time from the event date to get the amount of time between now and the event.

If less than one second remains until the event, the code disposes of the Timer, maximizes the form, and makes the form topmost. It then hides all of the form’s controls except lblFinished, which displays a message saying that the event has arrived. This branch of the if statement finishes by playing a “ta da” sound resource.

If more than one second remains until the event, the code updates the form’s labels to show the number of days, hours, minutes, and seconds remaining.

Theer’s one more odd detail. If you close the form, the form is destroyed but before the Timer is destroyed it might call its callback method. If that happens, the method tries to update controls that are already destroyed so the program throws an exception. Depending on the exact timing, this problem may not happen, so the program may run correctly many times and only crash occasionally and figuring out what went wrong can be difficult.

To prevent that, the program uses the following FormClosing event handler.

// Stop the timer.
private void Form1_FormClosing(object sender,
    FormClosingEventArgs e)
{
    if (TheTimer != null) TheTimer.Dispose();
}

This code simply disposes of the Timer if it was created.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in miscellany, system | Tagged , , , , , , , , , , , , | Leave a comment

Installing Visual Studio 2017

[Visual Studio 2017]

Microsoft claims that the Visual Studio 2017 installation is faster and uses less space than previous versions, and I think they’re right. The basic approach is to install only the bare bones initially and then make you install things that you need as you go along. It seems to be a reasonably effective approach.

To install Visual Studio 2017 Community (the free edition), follow these steps:

  1. Go to the download page and click the Free Download button. That downloads an executable that’s about 1 MB.
  2. Double-click the executable and let it do its thing. It will download and install the bare bones Visual Studio environment. This takes around 600 MB so it will take a few minutes. If you have a fast internet connection, it’s relatively quick. When it’s done, it will launch Visual Studio 2017.
  3. If you want to pin Visual Studio 2017 to the Start menu or taskbar, click on the Start menu (in the lower left corner of your screen) and type “Visual Studio 2017.” When you see Visual Studio 2017, right-click it and select Pin To Start or Pin To Taskbar.
  4. To install project templates, do this:
    1. Press Ctrl+Shift+N or open the File menu’s New submenu and select Project to start a new project.
    2. On the New Project dialog you’ll notice that the only template that is installed is a blank solution. At the bottom of the template list on the left, click the Open Visual Studio Installer link. When the UAC dialog asks you if you want to allow the installer to modify your system, click Yes.
    3. Click on the kinds of templates that you want to install. I installed .NET Desktop Development. That includes Windows Forms and WPF projects in C# and Visual Basic. It takes around 2.08 GB.
    4. After you make your selections, click the Modify button in the lower right corner. (A particularly bad name for this button. It’s the only button available, however, so eventually you have to stop looking for an Install button and click it to see what it does.)
    5. Wait. Depending on which templates you selected, this could take a while. If you install everything, it adds up to around 82.58 GB.
    6. After you install the new templates, the installer will need to reboot your system.

As in other recent versions, Visual Studio 2017 requires you to have a free developers account to run.

In every release, Microsoft adds lots of new features to try to convince you that it’s worth moving to the new version. A small sample of the features (some new and some not) include:

  • IDE support for English, Chinese (Simplified), Chinese (Traditional), Czech, French, German, Italian, Japanese, Korean, Polish, Portuguese (Brazil), Russian, Spanish, and Turkish.
  • Faster, smaller installation of Visual Studio.
  • Web: ASP.NET, HTML, JavaScript, CSS
  • Python
  • Azure
  • Data science and analytics
  • Office/SharePoint
  • Data: SQL Server, Azure Data Lake, Hadoop, …
  • Cross platform (Xamarin): Windows, Android, iOS, Linux, macOS
  • Mobile (JavaScript): Android, iOS, UWP
  • Games: C++, DirectX, Unreal, Cocos2d
  • More games: 2D and 3D games with Unity

Here are some links where you can get more information:

I’ll still stick with Visual Studio 2008 Express Edition for most of my posts because anything I write in that should be forward compatible with newer versions of Visual Studio, but you should download the new version and start playing with it.

If you find things that you particularly like or dislike, post then in comments below. (If you find problems, report them to Microsoft.)


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in IDE | Tagged , , , , , , , | 2 Comments

Use an improved extension method to calculate standard deviation in C#

[standard deviation]

The example Calculate standard deviation in C# makes an extension method that calculates standard deviation for an IEnumerable of integers.

Unfortunately because that example works with integers, it cannot work with other data types. Rian Meier showed me this method, which uses generics to work with other data types.

The new method applies to the generic type IEnumerable<T>. Ideally it would be nice to restrict the generic type T to numeric types, but C# doesn’t have a syntax for that.

Rian’s solution was to use the following code to test the elements in the IEnumerable to see if they can be converted into doubles.

double testDouble;
bool isNumeric = values.All(
    value => double.TryParse(value.ToString(), out testDouble));
if (!isNumeric)
    return double.NaN;

That works but I prefer to throw an exception instead of returning NaN. That way a programmer cannot accidentally think the returned result is a standard deviation. If there is a problem, it will be immediately obvious so the programmer can fix it.

The following code shows the new extension method.

// Return the standard deviation of an array of Doubles.
//
// If the second argument is True, evaluate as a sample.
// If the second argument is False, evaluate as a population.
public static double StdDev<T>(this IEnumerable<T> values,
    bool as_sample)
{
    // Convert into an enumerable of doubles.
    IEnumerable<double> doubles =
        values.Select(value => Convert.ToDouble(value));

    // Get the mean.
    double mean = doubles.Sum() / doubles.Count();

    // Get the sum of the squares of the differences
    // between the values and the mean.
    var squares_query =
        from double value in doubles
        select (value - mean) * (value - mean);
    double sum_of_squares = squares_query.Sum();

    if (as_sample)
    {
        return Math.Sqrt(sum_of_squares / (doubles.Count() - 1));
    }
    else
    {
        return Math.Sqrt(sum_of_squares / doubles.Count());
    }
}

The code first calls the original IEnumerable list’s Select method to “project” the original items into doubles and saves the result in a new IComparable<double>. If the items in the IEnumerable cannot be converted into doubles, this statement fails and throws an exception.

After this the method works exactly as before. See the previous example for information about calculating the standard deviation.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, extension methods, mathematics | Tagged , , , , , , , , , , | Leave a comment

Remove a TextBox control’s context menu in C#

[context menu]

Normally a TextBox control has a context menu that appears when you right-click it, but what if you don’t want that context menu? I mean, really. Am I required to have “Show Unicode control characters” and “Open IME” on every single TextBox?

In case you don’t know, “Open IME” toggles the Input Method Editor that lets you enter Chinese, Japanese, Korean, and other non-Latin characters from your keyboard. If you don’t use those languages, you don’t need it but it’s in the context menu anyway.

You can replace a TextBox control’s context menu with one of your own by adding a ContextMenuStrip to the form and setting the TextBox control’s ContextMenuStrip property equal to to it.

If you want to prevent any context menu from appearing, set the TextBox control’s ShortcutsEnabled property to false.

In this example, the top TextBox is normal and displays the default context menu when you right-click it. The second TextBox displays a custom context menu that has Copy, Cut, and Paste commands. The bottom TextBox has ShortcutsEnabled set to false so it doesn’t display any context menu.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls | Tagged , , , , , , , , , , | Leave a comment

Use ActiveControl to enabled and disable menu items in C#

[ActiveControl]

This program uses the ActiveControl property to determine what menu items should be enabled and disabled at any given moment. When the user opens a menu, only the appropriate items should be enabled. This example has Copy, Cut, and Paste menu items. The following list explains when they should be enabled.

  • Copy – Enabled when the active control is a TextBox and some of its text is selected.
  • Cut – Enabled when the active control is a TextBox and some of its text is selected.
  • Paste – Enabled when the active control is a TextBox and the clipboard contains text.

I have seen programs try to enable and disable menu items in all sorts of ways. Some try to figure out when a condition has changed (such as the user selecting text in a TextBox). Some even use a Timer to enable and disable menus every quarter second. That means the program does a huge amount of checking when nothing hasn’t actually changed.

A much easier solution is to enable and disable menu items when the menu is about to display. This example uses the following code to enable and disable its menu items.

private void EnableMenuItems()
{
    if (ActiveControl is TextBox)
    {
        TextBox txt = ActiveControl as TextBox;
        mnuEditCopy.Enabled = (txt.SelectionLength > 0);
        mnuEditCut.Enabled = (txt.SelectionLength > 0);
        mnuEditPaste.Enabled = Clipboard.ContainsText();
    }
    else
    {
        // Disable all commands.
        mnuEditCopy.Enabled = false;
        mnuEditCut.Enabled = false;
        mnuEditPaste.Enabled = false;
    }

    ctxCopy.Enabled = mnuEditCopy.Enabled;
    ctxCut.Enabled = mnuEditCut.Enabled;
    ctxPaste.Enabled = mnuEditPaste.Enabled;
}

This code is reasonably straightforward. It enables and disables the main menu’s Copy, Cut, and Paste commands depending on whether the active control is a TextBox, whether text is selected, and whether the clipboard contains text. It then gives the program’s context menu commands the same enabled states as the corresponding main menu commands.

So when do you call the EnableMenuItems method? A form’s main menu raises its DropDownOpening event when it is about to open. The following code calls EnableMenuItems when the Edit menu opens.

// Enable and disable items as appropriate.
private void mnuEdit_DropDownOpening(object sender, EventArgs e)
{
    EnableMenuItems();
}

This works differently for context menus because in some sense a context menu is the dropdown. Instead of using a context menu’s DropDownOpening event, the program looks for its Opening event as in the following code.

private void ctxEdit_Opening(object sender, CancelEventArgs e)
{
    EnableMenuItems();
}

Now when a menu or context menu is displayed, its commands are enabled as appropriate.

Note that this technique doesn’t work for toolbar commands or other objects that are always visible. In those cases you need to either leave the item enabled and just have it not do anything when the user invokes it, or detect changes to the rest of the program (like when the user selects text) and set the editability accordingly.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls | Tagged , , , , , , , , , , , | Leave a comment

Use the ActiveControl property in C#

[ActiveControl]

The ActiveControl property gives a reference to a container’s currently active control. For a form, ActiveControl doesn’t count menus, so a menu item can use ActiveControl to see which control was active when the menu was opened.

In this example, the menu items use ActiveControl to determine whether the currently active control is a TextBox and, if it is, they call that control’s Copy, Cut, or Paste methods.

The following code shows the example’s menu code.

// Copy from the currently active TextBox.
private void mnuEditCopy_Click(object sender, EventArgs e)
{
    if (ActiveControl is TextBox)
    {
        TextBox txt = ActiveControl as TextBox;
        txt.Copy();
    }
}

// Cut from the currently active TextBox.
private void mnuEditCut_Click(object sender, EventArgs e)
{
    if (ActiveControl is TextBox)
    {
        TextBox txt = ActiveControl as TextBox;
        txt.Cut();
    }
}

// Cut into the currently active TextBox.
private void mnuEditPaste_Click(object sender, EventArgs e)
{
    if (ActiveControl is TextBox)
    {
        TextBox txt = ActiveControl as TextBox;
        txt.Paste();
    }
}

in each case, the code determines whether the ActiveControl is a TextBox and, if it is, the code calls the appropriate TextBox method. It’s as simple as that.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls | Tagged , , , , , , , , , | Leave a comment