Archive

Archive for February, 2009

Computer Graphics – Assignment 2

February 24, 2009 Comments off

As I wrote previously, my Tuesday and Thursday afternoons are currently occupied in “academic pursuits” at the local Community College.  Over the last several weeks we have been working on Assignment 2, and just this past week a follow on assignment.  I have finished both of these, so as promised here are my recent graphics.

Assignment 2 – Company Logo

For this assignment, we were to create a logo for a company.  Most of us chose fictitious companies, so I chose “Grace Mandolins”, a custom mandolin luthiery.  Along with the company name, we were to select three keywords that we wanted our logo to convey.  For the logo, we had to produce three versions: full color, tinted, and black and white.  And then also for each one we had to produce a scaled down version.  My final image below is a single document representing all of these variations:

Logo Assignment, final version

Logo Assignment, final version

I did the B&W version first and I really liked it.  I’m not wild about the full color version, but once I understood Tinting and arrived at the tinted version above that quickly became my favorite.

Assignment 2A

The follow up assignment to the logo above was to then use the logo and create a business card.  This was largely a lesson in Typography, where we studied text sizing, alignment, fonts, etc.  I used the tinted approach and logo from above to create the following business card:

Business Card assignment final versiononline casino

Business Card assignment final version

I was pretty pleased with the way this turned out.  It breaks a couple of rules: it is largely centered and very balanced, but if it works, breaking a few rules is OK!

Categories: Miscellaneous

More Fun with WPF ScrollViewer

February 17, 2009 6 comments

In yesterday’s post, Fun with WPF ScrollViewer, I discussed how to detect when just the scroll bar was clicked on a draggable ListBox.  Today’s episode addresses something that happened to me on the other end: Dropping into the ListBox.

It probably makes sense that when a new item is dropped onto my ListBox, and therefore added to the list, I am setting the new item as the ListBox’s SelectedItem.  In theory, the ScrollViewer should automatically scroll the list so that the SelectedItem is in view.  In reality, this does not work (and I have it on good authority that it should.)  So in my scenario I am programmatically updating the SelectedItem, which now means I also need to programmatically instruct the ScrollViewer to scroll appropriately.

BringIntoView: The method that didn’t do anything

I want this code to run whenever the SelectionChanged event fires, so that is the method we will be using.  The first thing I tried was the BringIntoView method.  I tried it first on the ListBox itself, but realized that’s just silly since the ListBox is already in View.  What I really need is to tell the new SelectedItem to come into view.  If you have never done this, you may be surprised to find that you cannot cast the ListBox.SelectedItem object to a ListBoxItem: it is whatever type is DataBound to the List.  Instead, what I needed was a reference to the ListBoxItem that contains the SelectedItem.

In order to get the reference we need, we have to use the ListBox’s ItemContainerGenerator property.  This property exposes an ItemContainerGenerator object whose documentation is notably sparse.  But pull the object up in Intellisense and you’ll find a couple of useful methods, specifically ContainerFromItem and ContainerFromIndex.  We can use either one of these to retrieve a reference to the ListBoxItem container we need.  The code looks like this:

ListBoxItem item = (ListBoxItem)(ImageListBox.ItemContainerGenerator.ContainerFromItem(myListBox.SelectedItem));

Now that we have a reference to the ListBoxItem container, we can call its BringIntoView() method.

if (item != null)
{
    item.BringIntoView();
}

Unfortunately this was to no avail as it did not have the desired effect.  In fact, as far as I can tell, it had no effect, but it probably caused the ListBox’s RequestBringIntoView event to fire.  So, on to the next trial.

ScrollIntoView: The method that (almost) worked

Not to be thwarted, I began thumbing through Intellisense and found that ListBox has a method called ScrollIntoView.  For some strange reason, this sounded like it might be helpful, so I figured I’d give it a whirl.

ScrollIntoView (which is a really hard name to read in certain fonts because of the two lowercase ‘l’s followed by an uppercase ‘I’) requires that you pass it the object you want to scroll to, so we’ll pass it the ListBox.SelectedItem object:

myListBox.ScrollIntoView(myListBox.SelectedItem);

Now, if you run the code at first you will be lulled into a false sense of security.  This is the worst kind of bug, because it appears to work.  Change the SelectedItem and the ScrollViewer will adjust as necessary to scroll to the newly selected item… the first time.  What I found in subsequent drops to my ListBox was a very ugly bug.  It appears that the ScrollIntoView method gets caught in some kind of infinite loop, constantly resetting itself and causing the control display to gyrate wildly.  A little searching led me to this bug report at Microsoft.

This does not explain the exact same scenario, but it does exhibit the exact same results: an endless loop caused by a call to ListBox.ScrollIntoView(). Unfortunately, the bug is over a year old with no update or new information since it was accepted by Microsoft.

ScrollToHorizontalOffset: The method that does work

I was feeling pretty daunted at this point, but I decided to check one more thing before I quit for the day.  If I could get a reference to the ScrollViewer object itself, perhaps I could manually move it to the desired location.  I posted the code yesterday that I can use to retrieve the object reference, so all I had to do at this point was figure out what my options were for manually scrolling.

I found it in the ScrollToHorizontalOffset() method.  The method takes a double, which I mistakenly assumed was the number of screen units I wanted to scroll to, so I was trying to do a lot of math like measuring the ListBoxItem and multiplying the index number by the ActualWidth, and other pocket protector-y stuff like that.  Needless to say my first efforts were unrewarding.  I finally stumbled onto the fact the the HorizontalOffset indicates the index number of the item to scroll to – I was making it way too hard!  So all I had to do was pass the Selectedndex to the method and viola, a Scroll is born:

private void myListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (myListBox.SelectedIndex >= 0)
    {
                ScrollViewer scroll = myListBox.GetScrollViewer();
                double scrollPos = myListBox.SelectedIndex;
                scroll.ScrollToHorizontalOffset(scrollPos);
    }
}

Conclusion

I’m far from done with my drag and drop reorderable ListBox, but I’ve learned a lot about the VisualTree, item containers, and obviously the ScrollViewer. This code is certainly not set in stone: if you know another way to do this or have any recommendations for the above code, please share them below in the comments.

Categories: WPF

Fun with the WPF ScrollViewer

February 16, 2009 9 comments

In my current project, I have a horizontal ListBox wrapped in a ScrollViewer.  As you might expect, this indicates that I intend to have more content than my ListBox can display at any given time.  I am also implementing Drag and Drop reordering on this same ListBox.  This seemingly average task has turned out to be anything but, and I have spent the last couple of days fighting many issues, a couple of which are ScrollViewer specific.

Dragging and the scroll bar

The first problem I ran into was in initiating the Drag on the ListBox when the scrollbar was visible.  The problem is that the ScrollViewer is part of the default ListBox template, and the PreviewMouseLeftButtonDown event is wired to the ListBox.  This meant that if I tried to use the scroll bar, PreviewMouseLeftButtonDown would interpret it as a drag attempt and react accordingly.

In order to solve this, I needed to gain access to the ScrollViewer object that was part of the ListBox template, but there is no property for such an animal because the ListBox is completely unaware of the ScrollViewer.  And I could not access it directly because the ScrollViewer is not a named object within the Window, but rather it is part of the template.  So what’s a WPF developer to do?  The answer lies in navigating the VisualTree.

Navigating the VisualTree

In the code above, our XAML hierarchy ends at the ListBox:

Window
    LayoutRoot
        StackPanel
            ListBox

But the ScrollViewer lives inside the template definition of the ListBox.  So to access it at run time,we need to use the static VisualTreeHelper class.  To do that, we need to know what the template contains.  I used Blend to open a copy of the default ListBox Template which shows us the following hierarchy:

Template
    Border
        ScrollViewer
            ItemsPresenter

What we see is that the default ListBox template consists of a Border that holds a ScrollViewer that holds an ItemsPresenter.  This is important to visualize, because the ScrollViewer object we want is two levels into our ListBox, so we have to dig a little to get to it.  Our shovel for that digging is the VisualTreeHelper.GetChild() method.  I found this code posted by Matt Hohn at MSDN forums:

private ScrollViewer FindScroll()
{
    Border scroll_border = VisualTreeHelper.GetChild(PhotosListBox, 0) as Border;
    if (scroll_border is Border)
    {
        ScrollViewer scroll = scroll_border.Child as ScrollViewer;
        if (scroll is ScrollViewer)
        {
            return scroll;
        }
        else
        {
            return null;
        }
    }
    else
    {
        return null;
    }
}

In this code, Matt is using GetChild() to get the Border out of the Template.  The second time he uses the Child property to get the ScrollViewer from the Border.  I ended up moving this to an Extension Method so I could reuse it easily:

public static ScrollViewer GetScrollViewer(this ListBox listBox)
{
    Border scroll_border = VisualTreeHelper.GetChild(listBox, 0) as Border;
    if (scroll_border is Border)
    {
        ScrollViewer scroll = scroll_border.Child as ScrollViewer;
        if (scroll is ScrollViewer)
        {
            return scroll;
        }
        else
        {
            return null;
        }
    }
    else
    {
        return null;
    }
}

As you will see later, we will also need access to the ItemsPresenter within the ScrollViewer, so another simple Extension Method will do the trick:

public static ItemsPresenter GetItemsPresenter(this ListBox listBox)
{
    ScrollViewer scroll_viewer = listBox.GetScrollViewer();
    if (scroll_viewer is ScrollViewer)
    {
        ItemsPresenter list = scroll_viewer.Content as ItemsPresenter;
        if (list is ItemsPresenter)
        {
            return list;
        }
        else
        {
            return null;
        }
    }
    else
    {
        return null;
    }
}

Meanwhile, back at the Drag event…

So now that we can get a reference to the ScrollViewer, we have to determine whether or not the user is trying to scroll or drag an item within our ListBox.  To do this, we are going to start working in the ListBox_PreviewMouseLeftButtonDown event.  Remember that this event applies to the entire ListBox, so it will fire when the Scroll bar OR the ItemsPresenter are clicked.  To figure this out, we are going to check IsMouseOver to try to determine if the user clicked on the scroll bar or the actual items.  This gets a little interesting because the template hierarchy, and the inherent bubbling that occurs, means that when you click on the ItemsPresenter, both it AND the ScrollViewer will report IsMouseOver as true.  But if only the ScrollViewer is hovered over, then ItemsPresenter.IsMouseOver will report as false.

So we need references to both, and if ScrollViewer.IsMouseOver is true, but ItemsPresenter.IsMouseOver is false, then we can assume the user clicked on the scroll bar:

private bool IsScrolling { get; set; }
private void ImageListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    IsScrolling = false;

    ScrollViewer scroll = ImageListBox.GetScrollViewer();
    ItemsPresenter presenter = ImageListBox.GetItemsPresenter();
    if (presenter != null && scroll != null)
    {
        IsScrolling = (scroll.IsMouseOver && !presenter.IsMouseOver);
    }
}

We are storing the IsScrolling variable outside our method, because we are going to use it in the ListBox_PreviewMouseMove event to determine whether we are Scrolling or Dragging:

private void ImageListBox_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed && !IsDragging && !IsScrolling)
    {
        // Initiate drag code
    }
}

Enough fun for now

In my next post, I will discuss how to force the ScrollViewer to scroll to my SelectedItem when it is programmatically selected.

Categories: WPF

Roanoke Code Camp 3

February 11, 2009 2 comments

Roanoke Code Camp 2009 is happening in just a couple short weeks.

Roanoke Code Camp 2009

Description from the site:

The Roanoke Valley .NET User Group (RV.NUG) , with support from Microsoft, the International .NET Association (INETA) is hosting the third Roanoke Code Camp on Saturday, March 7th at Virginia Western Community College. This is an all-day, all-free event consisting of 4-5 tracks for a total of 20-25 presentations.  Topics include Visual Studio 2008, .NET Framework, SQL Server 2008 and SharePoint.

If you are a .NET developer in western Virginia, you can’t afford to miss this event!  An entire day of presentations on .NET, Sql Server, Sharepoint and more.  And best of all it’s FREE!

The slate of sessions looks awesome and includes some seriously talented people.  I am very excited to be among them: I’ll be presenting on WPF Templating and Data Binding using Expression Blend.  This will be my second time presenting at a Code Camp, and I am really looking forward to it.

If you have never been to a Code Camp before, you owe it to yourself to attend, so Register Today (it’s required), time is running out!

Categories: NUG

Must have Expression Add-ins

February 11, 2009 Comments off

Josh Holmes recently posted a list of Three Essential Expression Add-ins.  I didn’t even know there were such things, although I can’t say I’m surprised.  One of the Add-ins is XAML Intellisense for Blend, which I was recenlty told by a friend is supposed to be part of Blend 3.  Another one is called “Colorful Expression”, which provides access to Color Swatches available on the Internet.  I don’t know if they have it yet, but wouldn’t it be great to be able to export an entire swatch to a Resource Dictionary?

Apparently the Blend Add-in utility is not very user friendly, something I hope changes with Blend 3, but Josh does a great job of walking us through the nasty bits.  I can’t wait to try it myself.

— Hat tip to @adkinn on Twitter for posting this link.

Categories: Expression

Simple Image cropping in Expression Design

February 9, 2009 4 comments

I had a case today where I wanted to crop an image, something I haven’t needed to do in some time.  In fact, the last time I had to do it was on my previous computer which had several graphics programs installed.  This time, however, the only application I have installed on this machine is Expression Design 2.  I remember seeing the feature I was after in some training videos, so I thought I should be able to figure out quickly enough.  Unfortunately, it didn’t work as I remembered.  On the other hand, I found a pretty quick way to do simple cropping so I thought I’d share that.

First things first

Obviously, we need an image on our artboard, so I opened an image in Design:

I want to cut this down to just a head shot, but I can’t find a simple crop tool.  In my graphics class I’ve noticed that Illustrator suffers from this deficiency as well.  I’m sure it is because eof the vector orientation of these tools, but it seems to me it would be a standard feature.

What I remember from the videos is that I should be able to draw a rectangle over the image, denoting the crop location, select both objects, and perform an Intersection (or something like that), leaving only the cropped image behind.  Unfortunately, when I tried that the “Path Operations” options were disabled, so I must have been doing something wrong.  I stumbled around for a couple of minutes when I found something that worked: “Create Image Object.”

Create Image Object

Under the Object menu is a popout menu called “Image”.  This is where you’ll find the “Create Image Object” option:

Now drag a rectangle around the area you wish to retain.  Here’s the bad news: you only get one shot at this.  You can’t drop the rectangle and then tweak it, it has to be right immediately.  When you drop the rectangle, you will be prompted for the DPI of the new object.  The default is 96, which is the default WPF resolution (for lack of better terminology), so I just left it at that.  If you plan to print or need to retain really high quality, bump this up to around 300 DPI.

Save the Cropped Image

At this point you should see a rectangle on the image outlining the new Image object:

In fact, it IS the new Image object.  To prove this, just drag it to another part of the artboard:

Now, to save the cropped version of the Image, make sure just the new Image object is selected and go to File -> Export:

“Selected Objects” will be checked by default, so we are only dealing with the new Image object.  Change the Format, File Name, and Location to your desired parameters and press “Export All”.

Now you should have a quick and dirty cropped image.  I won’t use this all the time, because I can’t adjust the crop area, but for simple work like this it gets the job done quickly and easily.  Oh, and for the record, I did all the screen shots in this post using Design as well.

Categories: Design