Blog URL Change

by Jim Nuzzi 1. August 2008 14:15
Hey, this is just a quick post to let you all know that the URL for my blog has changed.

The old URL was blog.jimnuzzi.com and the new URL is simply www.jimnuzzi.com/blog.

Thank you all for reading and I will be posting again soon.

Tags:

General

WPF XAML MenuItem Styles

by Jim Nuzzi 29. June 2008 21:22

I recently began working with WPF for the first time.  I was doing this outside of my job on my own time (which is sometimes quite limited).  I had never worked with WPF before this venture.  I decided to download a trial copy of Microsoft Expression Blend 2 to check out the designer side of WPF.  The first thing that I noticed was the menus.  The menus had a black background with white text and the submenus had white borders and white menu separators (pictured below).  I decided that I liked this look and set out to implement this using Visual Studio 2008.  This entry describes how to create this menu.

Menu Example

I implemented the menu using two custom Styles.  The first for the Separator objects and the second for the MenuItem objects.  The XAML for the Separator style is as follows:

001<Style x:Key="MLB_Separator" TargetType="{x:Type Separator}">
002    <Setter Property="Margin" Value="0,3,0,3" />
003    <Setter Property="Template">
004        <Setter.Value>
005            <ControlTemplate TargetType="{x:Type Separator}">
006                <Grid>
007                    <Rectangle Height="1" Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Menu}}}" />
008                </Grid>
009            </ControlTemplate>
010        </Setter.Value>
011    </Setter>
012</Style>

As you can see in the code, The Separator style simply sets the default margins (line 2) and draws a 1px high rectangle using the parent Menu's foreground color (line 7).

For the MenuItem style, I started with the SimpleMenuItem style that was included when I was using Expression Blend. I found that this style was not complete and simply did not work correctly in some cases. After cleaning up that code and adding some additional features, I ended up with the XAML below:

001<Style x:Key="MLB_MenuItem" TargetType="{x:Type MenuItem}">
002    <Setter Property="Foreground" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Menu}}}"/>
003    <Setter Property="Template">
004        <Setter.Value>
005            <ControlTemplate TargetType="{x:Type MenuItem}">
006                <Border x:Name="Border"
007                        Background="{TemplateBinding Background}"
008                        BorderBrush="{TemplateBinding BorderBrush}"
009                        BorderThickness="{TemplateBinding BorderThickness}">
010                    <Grid>
011                        <Grid.ColumnDefinitions>
012                            <ColumnDefinition x:Name="Col0" MinWidth="17" Width="Auto" SharedSizeGroup="MenuItemIconColumnGroup"/>
013                            <ColumnDefinition Width="Auto" SharedSizeGroup="MenuTextColumnGroup"/>
014                            <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGTColumnGroup"/>
015                            <ColumnDefinition x:Name="Col3" Width="14"/>
016                        </Grid.ColumnDefinitions>
017
018                        <!-- ContentPresenter to show an Icon if needed -->
019                        <ContentPresenter Grid.Column="0" Margin="4,0,6,0" x:Name="Icon" VerticalAlignment="Center" ContentSource="Icon"/>
020
021                        <!-- Glyph is a checkmark if needed for a checkable menu -->
022                        <Grid Grid.Column="0" Visibility="Hidden" Margin="4,0,6,0" x:Name="GlyphPanel" VerticalAlignment="Center">
023                            <Path x:Name="GlyphPanelpath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,2 L0,4.8 L2.5,7.4 L7.1,2.8 L7.1,0 L2.5,4.6 z" FlowDirection="LeftToRight"/>
024                        </Grid>
025
026                        <!-- Content for the menu text etc -->
027                        <ContentPresenter Grid.Column="1"
028                                          Margin="{TemplateBinding Padding}"
029                                          x:Name="HeaderHost"
030                                          RecognizesAccessKey="True"
031                                          ContentSource="Header"/>
032
033                        <!-- Content for the menu IGT -->
034                        <ContentPresenter Grid.Column="2"
035                                          Margin="8,1,8,1"
036                                          x:Name="IGTHost"
037                                          ContentSource="InputGestureText"
038                                          VerticalAlignment="Center"/>
039
040                        <!-- Arrow drawn path which points to the next level of the menu -->
041                        <Grid Grid.Column="3" Margin="4,0,6,0" x:Name="ArrowPanel" VerticalAlignment="Center">
042                            <Path x:Name="ArrowPanelPath" HorizontalAlignment="Right" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,0 L0,8 L4,4 z"/>
043                        </Grid>
044
045                        <!-- The Popup is the body of the menu which expands down or across depending on the level of the item -->
046                        <Popup IsOpen="{Binding Path=IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" x:Name="SubMenuPopup" Focusable="false" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
047                            <Border x:Name="SubMenuBorder" BorderBrush="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Menu}}}" BorderThickness="1" Padding="2,2,2,2">
048                                <Grid x:Name="SubMenu" Grid.IsSharedSizeScope="True">
049                                    <!-- StackPanel holds children of the menu. This is set by IsItemsHost=True -->
050                                    <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/>
051                                </Grid>
052                            </Border>
053                        </Popup>
054                    </Grid>
055                </Border>
056
057                <!-- These triggers re-configure the four arrangements of MenuItem to show different levels of menu via Role -->
058                <ControlTemplate.Triggers>
059                    <!-- Role = TopLevelHeader : this is the root menu item in a menu; the Popup expands down -->
060                    <Trigger Property="Role" Value="TopLevelHeader">
061                        <Setter Property="Padding" Value="6,1,6,1"/>
062                        <Setter Property="Placement" Value="Bottom" TargetName="SubMenuPopup"/>
063                        <Setter Property="MinWidth" Value="0" TargetName="Col0"/>
064                        <Setter Property="Width" Value="Auto" TargetName="Col3"/>
065                        <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
066                        <Setter Property="Visibility" Value="Collapsed" TargetName="GlyphPanel"/>
067                        <Setter Property="Visibility" Value="Collapsed" TargetName="IGTHost"/>
068                        <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
069                    </Trigger>
070
071                    <!-- Role = TopLevelItem :  this is a child menu item from the top level without any child items-->
072                    <Trigger Property="Role" Value="TopLevelItem">
073                        <Setter Property="Padding" Value="6,1,6,1"/>
074                        <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
075                    </Trigger>
076
077                    <!-- Role = SubMenuHeader : this is a child menu item which does not have children -->
078                    <Trigger Property="Role" Value="SubmenuHeader">
079                        <Setter Property="DockPanel.Dock" Value="Top"/>
080                        <Setter Property="Padding" Value="0,2,0,2"/>
081                    </Trigger>
082
083                    <!-- Role = SubMenuItem : this is a child menu item which has children-->
084                    <Trigger Property="Role" Value="SubmenuItem">
085                        <Setter Property="DockPanel.Dock" Value="Top"/>
086                        <Setter Property="Padding" Value="0,2,0,2"/>
087                        <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
088                    </Trigger>
089                    <Trigger Property="IsSuspendingPopupAnimation" Value="true">
090                        <Setter Property="PopupAnimation" Value="None" TargetName="SubMenuPopup"/>
091                    </Trigger>
092
093                    <!-- If no Icon is present the we collapse the Icon Content -->
094                    <Trigger Property="Icon" Value="{x:Null}">
095                        <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
096                    </Trigger>
097
098                    <!-- The GlyphPanel contains the CheckMark -->
099                    <Trigger Property="IsChecked" Value="true">
100                        <Setter Property="Visibility" Value="Visible" TargetName="GlyphPanel"/>
101                        <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
102                    </Trigger>
103
104                    <!-- Using the system colors for the Menu Highlight and IsEnabled-->
105                    <Trigger Property="IsHighlighted" Value="true">
106                        <Setter Property="Background" Value="LightGray" TargetName="Border"/>
107                        <Setter Property="Foreground" Value="Black"/>
108                    </Trigger>
109                    <Trigger Property="IsEnabled" Value="false">
110                        <Setter Property="Foreground" Value="LightGray"/>
111                    </Trigger>
112                </ControlTemplate.Triggers>
113            </ControlTemplate>
114        </Setter.Value>
115    </Setter>
116</Style>

The MenuItem style first sets the foreground color to the parent Menu's foreground color (line 2). Then comes the Template, which is where it gets interesting. The Template starts with a Border around a Grid. The Grid has 4 ColumnDefinition items. The first is for the icon or the checkbox (depending on the type of MenuItem). The second is for the text of the MenuItem. The third is for the input gesture text (e.g. Ctrl-S). The last is for the arrow, if the MenuItem contains a sub-menu.

The contents of the columns are then defined. First is a ContentPresenter that will display the value of the "Icon" property. Next is a Grid that will hold the checkbox, if needed. These are both displayed in the first column of the main Grid (but not at the same time). After this is another ContentPresenter that will display the value of the "Header" property. Next is another ContentPresenter that will display the value of the "InputGestureText" property. Then there is a Grid that will display the arrow if there is a sub-menu. Finally, there is a Popup that will display the sub-menu (if one is defined).

The remainder of the Style contains the Trigger items that will manipulate what is displayed based on the type of MenuItem (top-level menu item, sub-menu meu item, etc.) that is being rendered. I will leave these items for a future entry.

Tags: , , , , , , ,

.NET | WPF

Welcome, Jury Duty, and Technology

by Jim Nuzzi 11. June 2008 08:42

Hello, this is my first entry for my personal technology blog. I hope to provide some useful information and even some rants & ramblings here on my blog. I would love to hear your feedback, so please post comments about my blog entries.

I am actually writing this blog entry from the Ninth Judicial Circuit Court of Florida as I perform my civic duty (Jury Duty). So I thought I would start off my blog by discussing some of my thoughts, findings, and observations about Jury Duty and even about how technology plays a role in Jury Duty today.  Well, here it goes...

First, I strongly urge everyone to perform their civic duty and appear when you are summoned for Jury Duty. This is a very important part of the system of checks and balances in our country. I am sure that most of you are aware of the role of the Juror, in its most basic form. That being to provide a trial by peers for an individual (or entity) after they have been accused of a crime. You may also be aware that you could be sitting on a civil trial, which means the defendant is not being accused of a crime. Even though the defendant is not being accused of a crime, this is still a very important role for a Juror.

The aspect of serving as a Juror that most people are not aware of can be summed up in two words, "Jury Nullification". The definition of Jury Nullification at Wikipedia is as follows:

> Jury nullification is any rendering of a verdict by a trial jury, acquitting a criminal defendant despite the defendant's violation of the letter of the law. This verdict need not disagree with the instructions by the judge concerning what the law is, but may disagree with an instruction, if given by the judge, that the jury is required to apply the law to the defendant if certain facts are found. > Although a jury's refusal relates only to the particular case before it, if a pattern of such verdicts develops in response to repeated attempts to prosecute a statutory offense, it can have the practical effect of disabling the enforcement of the statute. "Jury nullification" is thus a means for the people to express opposition to an unpopular legislative enactment.

What this means to us in the United States of America is that we, as Jurors, can effectively nullify a law that we find oppressive, unjust, or simply not valid. This is, arguable, the most important aspect of serving as a Juror. This is the last check in our system that ensures our government does not oppress or discriminate against anyone in our country and that our lawmakers are performing the duties that we elected them to perform.

Hopefully you are now at least slightly more informed and willing to appear when you are summoned for Jury Duty. So with that out of the way, I would like to discus how technology plays an important role in Jury Duty today.

My first observation regarding technology and Jury Duty was the court's website. There was plenty of useful information including videos, instructions, and even the ability to fill out your Juror questionnaire on-line. You can even check on-line if you are required to appear for Jury Duty (as well as by phoning in). I actually found these features quite useful in the days/weeks leading up to the date that I was summoned for.

After arriving at the courthouse, passing through the security screening, and making my way into the Jury waiting room I was pleasantly surprised. The room had, somewhat, comfortable chairs, tables, power outlets for electronic devices, a TV room for watching TV, an "Internet Cafe" with PC's for Juror use, and wireless Internet access. The wireless network was unsecured (so be careful if you wish to do any on-line banking or something similar) and was gated by a Cisco device that forced you to accept a usage policy before connecting. This was a little inconvenient since I dropped my wireless connection a few times and had to go through this every time I did. Still, being able to post this blog entry while waiting to be called was well worth it. Especially since the wireless Internet access was freeSmile

What I did not enjoy was the fact that the coffee was not free. There was a little room with vending machines and vendor with a table set up selling coffee, bagels, etc. to the Jurors. What made this even more frustrating was that they only accepted cash and, of course, I did not have any. So I proceeded to the ATM, which is located in the main lobby of the courthouse, only to find that it is out of order. I ask someone were I can find another ATM and they pleasantly inform me that it is located across the street at the Bank of America. Now I have to leave the courthouse, go across the street to the ATM, get my cash, come back across the street to the courthouse, go through the security screening again, and then, finally, get my coffee and bagel. As Igor said in Young Frankenstein, "It could be worse... It could be raining". Laughing

Well, I think that's it for today.  I need to go get questioned as a prospective Juror.

Tags: , , ,

General

About the author

Jim Nuzzi Jim Nuzzi
Software Engineer/Architect

All-Around Good Guy

View James Nuzzi's LinkedIn profileJim's LinkedIn profile
Send mailContact Jim

Recent posts

Recent comments

Comment RSS

Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's, or anyone else's, view in any way.

© Copyright 2008

Valid XHTML 1.0 Transitional

Valid CSS!