1/29/2008 3:24:00 PM

Zooming with the Mouse Wheel in WPF

Not exactly sure if one could refer to this as "real zooming" or whatever, but it's a nifty trick that I've been thinking about implementing for a few days and finally had the time to do so. With that said, let's get to it. The point of this post is to explain how to allow for users who would like to zoom in on (or increase the size of, to be specific) specific controls on a WPF window. The code to do this is surprisingly simple. In fact, I'd be interested to see any improvements on this method.

The XAML code for a sample window is below. Note that I've just added one simple Rectangle to the window's Grid and attached the MouseWheel event to my local OnMouseWheel event handler. I'll examine the code for the OnMouseWheel handler in a moment, but for now here's some really simple XAML.

    5       <Grid>

    6         <Rectangle MouseWheel="OnMouseWheel" Width="100" Height="100" Name="rectangle1">

    7             <Rectangle.Fill>

    8                 <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">

    9                     <GradientStop Color="ForestGreen" Offset=".1"/>

   10                     <GradientStop Color="Khaki" Offset=".6"/>

   11                 </LinearGradientBrush>

   12             </Rectangle.Fill>

   13         </Rectangle>

   14     </Grid>

Of course, here's the handler method. In it, I examine the sender parameter as a FrameworkElement, as that's the base class for the majority of the controls for which I'd like to provide zoomability. Sure, I made the word up. Quit being cynical and look at the code.

   27         private void OnMouseWheel(object sender, MouseWheelEventArgs e)

   28         {

   29             FrameworkElement source = sender as FrameworkElement;

   30             if (source == null) return;

   31             source.Width = rectangle1.Width + (e.Delta / 10);

   32             source.Height = rectangle1.Width + (e.Delta / 10);

   33         }

That's it. You can attach this event handler to the MouseWheel event of any control that inherits from FrameworkElement and provide zoomability for your users.

Happy coding! 

Kick it! | del.icio.us | Comments (1) | Permalink

12/18/2007 10:01:00 AM

WPF and ASP.Net Metaphor

LearnWPF.com has a great article that draws a correlation between the ASP.Net Repeater and how to achieve the same functionality within WPF. An excellent way of thinking about WPF from a web developer's perspective, drawing on familliar functions to explain a new methodology. Always a good approach.

Kick it! | del.icio.us | Comments (0) | Permalink

12/7/2007 5:06:00 PM

Great paper on XAML

This paper describes the way XAML transforms the relationships between designers and developers. Excellent read.

Kick it! | del.icio.us | Comments (0) | Permalink

12/7/2007 4:03:00 PM

WPF Conditional DataBinding

I've been learning a good deal recently about WPF. Granted, I've not yet moved into the VS2008 world (I think that'll happen this weekend) so some of this code might not work properly under it. Nevertheless, I was working this week on a WPF application requiring the use of logical choices during DataBinding. I hadn't done anything conditional during my DataBinding, and finding a good example on just how to do it led me in a lot of different directions.

<rant>
That's the thing that's been bugging me about WPF, that there's so many alpha, beta, omega, RC, and other sorts of bits out there, that a lot of times the examples are moot by the time I find them. But that's another blog post...
</rant>

Point is, I wanted to demonstrate conditional logic during databinding in as simple a method as possible. As you'll find throughout the samples, one of the main tools you have to do this sort of thing is the System.Windows.Data.IValueConverter interface. In the following example I'll show you how to use this interface (or rather, your own class implementing the interface) to achieve logical decision-making during DataBinding in your WPF applications. 

As is the case in most WPF DataBinding scenarios, I'll first make a class that will serve as the entity to be displayed in a list control. The Person class, the code for which is displayed below, will be used as our entity. As we add Person instances to the list box, we'll choose to color each name red or blue. Red names will indicate female persons, whereas blue names will indicate male persons. It's remedial, true, and maybe even a little politically incorrect for those more sensitive audience members, but we like simple. Simple is good when you're learning. Moving on, here's our Person class definition.

   30     public class Person
   31     {
   32         private string _name;
   33         private Gender _gender;
   34 
   35         public Person(string name, Gender gender)
   36         {
   37             _name = name;
   38             _gender = gender;
   39         }
   40 
   41         public Gender Gender
   42         {
   43             get { return _gender; }
   44             set { _gender = value; }
   45         }    
   46 
   47         public string Name
   48         {
   49             get { return _name; }
   50             set { _name = value; }
   51         }
   52     }
   53 
   54     public enum Gender
   55     {
   56         Male,
   57         Female
   58     }

Next will be the creation of a class that the XAML code can use during run-time. This class will expose an instance of a List<Person> to which the list box control will be bound.

    8     public class PersonDataSource
    9     {
   10         public PersonDataSource()
   11         {
   12             _people = new List<Person>();
   13             _people.Add(new Person("John Dilworth", Gender.Male));
   14             _people.Add(new Person("Anna Humphries", Gender.Female));
   15             _people.Add(new Person("Brady Gaster", Gender.Male));
   16             _people.Add(new Person("Sam Kinison", Gender.Male));
   17             _people.Add(new Person("Julie Knowles", Gender.Female));
   18         }
   19 
   20         private List<Person> _people;
   21 
   22         public List<Person> People
   23         {
   24             get { return _people; }
   25         }
   26     }

Since we're going to make a decision during the DataBinding we'll need to come up with how we're going to choose the red text or the blue text. To do this, we'll finally get around to creating our own custom converter. The Convert method implementation is what you'll want to pay attention to below.

   61     public class PersonColorConverter : System.Windows.Data.IValueConverter
   62     {
   63         #region IValueConverter Members
   64 
   65         public object Convert(object value, Type targetType, object parameter, 
System.Globalization.CultureInfo culture)
   66         {
   67             Gender gender = (Gender)value;
   68             if(gender == Gender.Male) return System.Windows.Media.Brushes.Blue;
   69             if(gender == Gender.Female) return System.Windows.Media.Brushes.Red;
   70             return System.Windows.Media.Brushes.Black;
   71         }
   72 
   73         public object ConvertBack(object value, Type targetType, object parameter, 
System.Globalization.CultureInfo culture)
   74         {
   75             throw new Exception("The method or operation is not implemented.");
   76         }
   77 
   78         #endregion
   79     }

Next, the XAML. Note especially lines 5 and 10 below. Line 5 will point the XAML at an actual CLR namespace in which a "class to be used by the XAML" lives. Line 10 declares an instance of a particular class from said namespace (an instance of the PersonDataSource class) the XAML list box will use as a data source.

    1 <Window x:Class="WpfExamples.DataBindingLogic.Window1"
    2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4     Title="WpfExamples.DataBindingLogic" Height="300" Width="300"
    5     xmlns:local="clr-namespace:WpfExamples.DataBindingLogic"
    6     >
    7 
    8     <Window.Resources>
    9 
   10         <local:PersonDataSource x:Key="dataSource"/>

Next, we'll declare an instance of the custom converter class in our XAML file that will be used by the list box during data binding. 

   11         <local:PersonColorConverter x:Key="converter"/>

Finally, we'll provide a DataTemplate that will instruct each ListBoxItem on how it should display itself. You'll also see the code for the list box below, inclusive with typical DataBinding syntax.

   13         <DataTemplate DataType="{x:Type local:Person}">
   14             <ListBoxItem Content="{Binding Path=Name}" 
Foreground="{Binding Path=Gender, Converter={StaticResource converter}}"/>
   15         </DataTemplate>
   16 
   17     </Window.Resources>
   18 
   19     <Grid>
   20         <ListBox Width="200" Height="300" 
ItemsSource="{Binding Source={StaticResource dataSource}, Path=People}"/>
   21     </Grid>
   22 
   23 </Window>

When run, you'll see the result - a simply-styled list box, one glance at which and you know what to expect.

Happy coding! 

Kick it! | del.icio.us | Comments (2) | Permalink