Architect or Cobbler?
Good code starts with good design

Adding some Dialogs to Scribble

Saturday, November 18, 2006

I'm going to add a dialog to the Scribble app so I can change the thicknesses of the pen lines.  The dialog will look like this

To do this you need a Window to represent the GUI, so I created a new Xaml file PenWidthDialog.xaml, gave it a border, a 4X4 grid, two text boxes and two buttons.  The only work at this stage is to set the IsDefault and IsCancel properties on the appropriate buttons.  I've also set the TabIndex and IsTabStop properties as you need to be able to tab through a dialog properly.

  <Border BorderThickness="2">

    <Grid Background="LightGray">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="20" />
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="80" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
        <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <Label  Grid.Column ="1" Grid.Row="1">Thin Pen Width</Label>
      <Label Grid.Column ="1" Grid.Row="2">Thick Pen Width</Label>
      <TextBox Grid.Column ="2" Grid.Row="1" Margin ="0,2,0,6" 
               IsTabStop="true" TabIndex="0">
      </TextBox> 
      <TextBox Grid.Column ="2" Grid.Row="2" Margin ="0,2,0,6" 
               IsTabStop="true" TabIndex="1" >
      </TextBox>
      <Button Grid.Column ="3" Grid.Row="1" Height="25" Width="70" 
Name="OKButton" Click="OnOkButtonClicked" IsTabStop="true"
TabIndex="2" IsDefault="True">OK</Button> <Button Grid.Column ="3" Grid.Row="2" Height="25" Width="70"
Name="CancelButton" IsTabStop="true" TabIndex="3"
IsCancel="True">Cancel</Button> </Grid> </Border>

Now I want to add the data bindings for the Pen Width, and immediately I realise I need a bit of refactoring, so I create a Pen class with 3 properties, ThinWidth, ThickWidth and InkColor.  In my ScribbleCanvas class I create a new Pen and attach it to the canvas, and remove the old int properties that described thick and thin pens.

Now change Scribble.Xaml to add an event handler for the menu PenWidths, by adding a Click property.  The implementation of the event handler is a doddle, create a new PenWidth dialog object and show it using the ShowDialog method.  This returns a bool? , so it is important you handle the null value that is returned if the user closed the dialog with the X.  The simplest way to do this is to use the GetValueOrDefault method, which will convert a null to false.  If you clicked OK then simply call the ChangePenWidths() method to propagate the changes to all canvases.  Before you do this you have to set the static Pen property to the new Pen from the dialog.

        void OnChangePenWidths(object sender, RoutedEventArgs e){
            PenWidthDialog pwd = new PenWidthDialog();
            pwd.Owner = this;
            if (pwd.ShowDialog().GetValueOrDefault())
            {
                ScribbleCanvas.ChangePen();
                ChangePenWidths();
            }
        }

You can compile and run this, and though the dialog works, nothing will happen yet.  The reason is obvious, we haven't bound the text boxes to any data, so we'll fix that right now.  In WPF a control attempts to bind to a DataContext, and it will simply search up it's control tree till it finds a non-null DataContext and use this as the data source.  Then you use the Binding element to attach to this context. The binding has a Path property, which describes the property in the context that you wish to bind against. In our case this will be the ThinWidth and ThickWidth properties of the Pen object that belongs to the ScribbleCanvas.  To set up this data context I'm going to add an initialisation method that is invoked by adding the Loaded property to my Xaml, I'm also going to take the opportunity to add my WPFScribble namespace into the Xaml as I know I need it just now, as in:

<Window x:Class="WPFScribble.PenWidthDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:WPFScribble" 
    Title="Pen Widths" Height="150" Width="300" ResizeMode="NoResize"
    Loaded="OnInit"
    >

In the OnInit method I'm going to load the DataContext with the Pen object that I want to bind to.

        private void OnInit(object sender, RoutedEventArgs e)
        {
            this.DataContext = ScribbleCanvas.ScribblePen;
        }

Finally you add the binding that will bind the properties to the text boxes.  To do this you  need to add either a Binding element to the Text property or  attach a {Binding} statement directly to the text box.   Both syntaxes are shown below.

      <TextBox Grid.Column ="2" Grid.Row="1" Margin ="0,2,0,6" 
               IsTabStop="true" TabIndex="0">
        <TextBox.Text>
          <Binding Path="ThinWidth" 
                   UpdateSourceTrigger="LostFocus" />
        </TextBox.Text>
      </TextBox> 
      <TextBox Grid.Column ="2" Grid.Row="2" Margin ="0,2,0,6" 
               IsTabStop="true" TabIndex="1" Text="{Binding Path=ThickWidth}" />

You can run your application now, and changing Pen widths will work, well to a point.  Open up the dialog and make the thin width 3 and the thick width a.  Clearly this is a nonsensical value, but the GUI is quite happy to accept this.  Oops, we need to add validation.  WPF only comes with one validator the ExceptionValidationRule, which fires if an exception is thrown when updating the binding.  This isn't good enough for our needs, so we need to create our own validator.  To do this you subclass ValidationRule, provide any properties you need, such as a minimum and maximum value, and override the Validate method.  This returns a ValidationResult, as shown in the code below.

    public class PenWidthRule : ValidationRule
    {
        private int _min;
        private int _max;

        public PenWidthRule()
        {
        }

        public int Min
        {
            get { return _min; }
            set { _min = value; }
        }

        public int Max
        {
            get { return _max; }
            set { _max = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            int age = 0;

            try
            {
                if (((string)value).Length > 0)
                    age = Int32.Parse((String)value);
            }
            catch (Exception e)
            {
                return new ValidationResult(false, "Illegal characters");
            }

            if ((age < Min) || (age > Max))
            {
                return new ValidationResult(false,
                  "Please enter an age in the range: " + Min + " - " + Max + ".");
            }
            else
            {
                return new ValidationResult(true, null);
            }
        }
    }

You want the GUI to invoke the validation, so you need to add the validation rules to the Binding, as shown in the Xaml fragment below.  If the validation fails, then the WPF framework will surround the text box with a red surround. 

         <Binding Path="ThinWidth" 
                   UpdateSourceTrigger="LostFocus" >
            <Binding.ValidationRules>
              <src:PenWidthRule Min="1" Max="30" />
            </Binding.ValidationRules>
          </Binding>   

You may want to have a custom validation message, to do this you need to change the style of the text box.  We'll leave this till tomorrow :-)  For now you can download the source for the project from here.


# posted by James @ 3:43 PM   6 comments Comments: I keep listening to the news speak about getting free online grant applications so I have been looking around for the best site to get one.
# posted by Anonymous Anonymous @ 11:06 AM   Ich entschuldige mich, aber meiner Meinung nach irren Sie sich. Ich biete es an, zu besprechen. viagra kaufen schweiz cialis preis [url=http//t7-isis.org]viagra preissuche[/url]
# posted by Anonymous Anonymous @ 1:28 AM   Algo no sale asГ­ http://nuevascarreras.com/ cialis generico barato Bravo, hai appena visitato un'altra idea [url=http://nuevascarreras.com/tag/cialis-online/ ]cialis precios [/url]
# posted by Anonymous Anonymous @ 12:57 AM   Si sono errati. Io propongo di discuterne. Scrivere a me in PM, ti parla. [url=http://lacasadicavour.com/eriacta/ ]acquisto cialis generico [/url]A mio parere, si sbaglia. Cerchiamo di discutere di questo. Scrivere a me in PM. http://lacasadicavour.com/kamagra/ cialis acquistare Bravo, la tua idea ГЁ molto buona
# posted by Anonymous Anonymous @ 3:25 PM   Great stuff [url=http://itkyiy.com/lasonic-lta-260/]lta chile[/url] just fine [url=http://itkyiy.com/methylprednisolone-acetate/]methylprednisolone and alcohol[/url] was loud [url=http://itkyiy.com/sces/]sce discounts[/url] something bad [url=http://itkyiy.com/k-chlor/]atenolol chlor[/url] his monster [url=http://itkyiy.com/epipen-online-video/]epipen and production and cost[/url] objection that [url=http://itkyiy.com/bio-identical-estrogens/]overweight women estrogens hairy[/url] are those [url=http://itkyiy.com/vertigo-meclizine/]side effects of meclizine[/url] too true [url=http://itkyiy.com/goody's-credit-card-bill/]goody's warn notice[/url] the completion [url=http://itkyiy.com/sodium-xylene-sulfonate/]barium diphenylamine sulfonate[/url] for show [url=http://itkyiy.com/technetium-99m/]technetium ecd[/url] large but [url=http://itkyiy.com/siberian-ginseng-increasing-testosterone/]ginseng and medicine[/url] much cake [url=http://itkyiy.com/dr-jonas-salk-biography/]salk contemporary[/url] words exactly [url=http://itkyiy.com/fond-du-lac-reservation-tribal-enrollment/]fond du lac wi newspaper[/url] own eyes [url=http://itkyiy.com/tramadol-vs-vicodin/]online pharmacy vicodin hydrocodone[/url] the room [url=http://itkyiy.com/removing-chlorine-with-sodium-thiosulfate/]sodium thiosulfate vs hydrochloric acid[/url] young woman [url=http://itkyiy.com/peekaboo-petites/]cleo petites[/url] their sea [url=http://itkyiy.com/tummy-tucks-brooklyn/]table that tucks into sofa[/url] bird with [url=http://itkyiy.com/turbo-backup-pep/]pep plus turbo backup[/url] other necessitie [url=http://itkyiy.com/diphenhydramine-lawsuits/]diphenhydramine hcl for sleep[/url] omething bothered [url=http://itkyiy.com/ethyl-epa-purified/]purified compressed air[/url] most feasible profanity.
# posted by Anonymous Anonymous @ 10:31 AM   Hi,

When ever I surf on web I come to this website[url=http://www.weightrapidloss.com/lose-10-pounds-in-2-weeks-quick-weight-loss-tips].[/url]You have really contiributed very good info here www.wintersfamily.plus.com. Do you pay attention towards your health?. Here is a fact for you. Research shows that almost 70% of all USA adults are either fat or weighty[url=http://www.weightrapidloss.com/lose-10-pounds-in-2-weeks-quick-weight-loss-tips].[/url] Hence if you're one of these citizens, you're not alone. In fact, most of us need to lose a few pounds once in a while to get sexy and perfect six pack abs. Now next question is how you can achive quick weight loss? Quick weight loss can be achived with little effort. If you improve some of your daily diet habbits then, its like piece of cake to quickly lose weight.

About me: I am writer of [url=http://www.weightrapidloss.com/lose-10-pounds-in-2-weeks-quick-weight-loss-tips]Quick weight loss tips[/url]. I am also health expert who can help you lose weight quickly. If you do not want to go under difficult training program than you may also try [url=http://www.weightrapidloss.com/acai-berry-for-quick-weight-loss]Acai Berry[/url] or [url=http://www.weightrapidloss.com/colon-cleanse-for-weight-loss]Colon Cleansing[/url] for effective weight loss.
# posted by Anonymous Anonymous @ 4:54 PM   Post a Comment

<< Main blog page
This page is powered by Blogger. Isn't yours?