Posts Tagged ‘WPF’

Be careful with Default-Values of Dependency-Properties if you’re using Reference-Types.

Thursday, February 11th, 2010

I’ve justed finished a small PieMenu for a WPF-Application for one of our customers in switzerland. The PieMenu is displayed below with a black-red-style. The Style, colors and items can be changed individually. The colors and icons etc. in the PieMenu below are just the ones I’ve created for testing purposes.

image

While developing this PieMenu I’ve implemented several Dependency-Properties. Some of them containing ObservableCollections as Default-Values like this:

static PieMenu()
{
 LeftSubItemsProperty = DependencyProperty.Register(
  "LeftSubItems", typeof (ObservableCollection<PieMenuItem>),
  typeof (PieMenu), new UIPropertyMetadata(
  new ObservableCollection<PieMenuItem>()));
  ...
}

I developed, made some UI-Tests, developed, made some UI-Tests and so on and everything was fine. But only till I’ve placed a second PieMenu in my Test-App. All Items of PieMenu1 and PieMenu2 were contained in PieMenu1 and PieMenu2. If you see the line above you can image what happened, if you sit in front of your code with at least 1000 lines of code in the PieMenu-class, you have to search a bit.

In the line above the ObservableCollection created as a Default-Value for the Dependency-Property is of course a static one, because the Dependency-Property is stored in a static variable and as you see in the code-snippet above it is initialized in the static constructor of the PieMenu-class. There’s no instance around at this point.

In other words that means every PieMenu that won’t explicitly specify an ObservableCollection gets the Default-Value, and that’s a static one that will be shared over all PieMenus in your app. So all the Items of every PieMenu are in every PieMenu. Isn’t that amazing? :-)

The solution I’ve used is straight forward. Just create the Dependency-Property with a null-reference as its default-value:

static PieMenu()
{
 LeftItemProperty = DependencyProperty.Register(
  "LeftItem", typeof (PieMenuItem), typeof (PieMenu),
  new UIPropertyMetadata(null));
}

In the Instance-Constructor assign a new ObservableCollection to the Dependency-Property and you’re fine.

public PieMenu()
{
 LeftSubItems = new ObservableCollection<PieMenuItem>();
 ...
}

Keep in mind that setting a local value in the Constructor won’t let you set this value in a Style anymore. But for the PieMenu and the ObservableCollection that won’t matter. You’re just adding and removing elements, you don’t want to define this Collection in a Style.

So, as you see in this post, you’ve to implement Dependency-Properties with Default-Values that are reference-types with caution.

Happy coding! ;-)

WPF Printing: How to print a PageRange with WPF’s PrintDialog – that means the user can select specific pages and only these pages are printed

Tuesday, November 24th, 2009

Printing a Page Range isn’t as easy as it supposed to be. So in this blog-post you’ll see a very easy method to print specific pages from a XPS-Document. But before we look at the solution, let’s start with the problem.

The Problem

WPF’s PrintDialog has a UserPageRangeEnabled-Property. Set this property to true before you show the PrintDialog. Then the user is allowed to enter a Pagerange in the PrintDialog. The problem is that whatever the user enters, in each case all pages are printed. The PrintDialog itself has no logic to print some specific pages. Let’s look at an example.

Below the small UI that consists of a Button and a DocumentViewer. This code belongs to the MainWindow.xaml-File.

<Button Content="Print" Click="PrintButtonClick"
        Margin="10"
        HorizontalAlignment="Left"
        Width="75"/>
<DocumentViewer x:Name="viewer" Grid.Row="1"/>

The Codebehind-File MainWindow.xaml.cs has an EventHandler for the Loaded-Event of the Window. There a XPS-Document with five pages is loaded into memory. The FixedDocument-Instance contained in that XPS-Document is stored in the _fixedDocument-Field and displayed in the DocumentViewer called viewer – the latter we declared above in XAML.

public partial class MainWindow : Window
{
 private FixedDocument _fixedDocument;

 public MainWindow()
 {
   InitializeComponent();
 }

 private void OnLoaded(object sender, RoutedEventArgs e)
 {
    // Load the FixedDocument
  var document = new XpsDocument("FivePagesDocument.xps",
                                   FileAccess.Read);
  var sequence = document.GetFixedDocumentSequence();
  _fixedDocument = sequence.References[0].GetDocument(false);

    // Assign it to the viewer
  viewer.Document = _fixedDocument.DocumentPaginator.Source;
 }

So we have the necessary thing for testing a “print-range”-scenario: A FixedDocument-Instance in memory, stored in the _fixedDocument-Field. Let’s look at the PrintButtonClick-Eventhandler that contains the logic to print. The Eventhandler is shown below. First a PrintDialog is created. Then we set the UserPageRangeEnabled-Property to true, show the Dialog by calling the ShowDialog-Method. Is the return-value true we call the PrintDialog’s PrintDocument-Method by passing in the DocumentPaginator of the FixedDocument. Also a string is passed in that is displayed in the printer queue as jobname.

void PrintButtonClick(object sender, RoutedEventArgs e)
{
  var dlg = new PrintDialog();

  // Allow the user to select a PageRange
  dlg.UserPageRangeEnabled = true;

  if (dlg.ShowDialog() == true)
  {
    DocumentPaginator paginator =
      _fixedDocument.DocumentPaginator;
    dlg.PrintDocument(paginator, "Just a test");
  }
}

Now what happens? Let’s look how we use the application. When starting up the application, the FixedDocument with five pages is displayed in the DocumentViewer:

image

When the “Print”-Button is pressed, the PrintDialog comes up. I select a PageRange of 2-3 like shown below. For testing purposes I always print in the PDFCreator that creates a PDF-Document with the output. There are several other ways. You could also print in the XPS-Document-Writer (even if it’s a little bit doubled when printing a xps to the XPS-Document-Writer).

image

Now even with the Pages of 2-3 selected, the “printed” PDF looks like below. It contains all five pages of my document. But it should contain only the pages 2 and 3.

image

So let’s summarize the problem: It doesn’t matter what you select as a PageRange in the PrintDialogs Pages-Field. It’s up to you to check the Pages and print out only that range. The PrintDialog doesn’t care anything about the PageRange.

The PrintDialog has the Property PrintRange that contains a PrintRange–object with PrintFrom- and PrintTo-Properties. It also has a Property called PageRangeSelection that contains the value PageRangeSelection.UserPages when a PageRange was entered. But the logic to print out that specified range is your work. And this work needs some WPF know-how to do. So let’s look at the solution(s). :-)

A bad solution

I call the first one a bad solution because it is not an easy to manage one. This solution is to make a new FixedDocument that only contains the pages you need. You can implement such a logic based on the things you find in this codeproject-article:

http://www.codeproject.com/KB/vb/reording_xps.aspx

In my mind creating a new XPS-Document just for printing is a bad solution. I think a good solution would be to just be able to print some pages of an existing xps-Document/FixedDocument. So let’s look at the good one.

A good solution (I hope so ;-) )

The good solution is the one I’ve implemented today and finished in the train from Zurich to Basel. I’ve not tested every scenario, but it seems to work great. If you have any hints to this solution, let me know.

The first thing you have to know is that the pages used for the output are created by a DocumentPaginator. This was passed to the PrintDocument-Method of the PrintDialog some lines above. The DocumentPaginator-class itself is abstract. Beside some members it defines a Method GetPage(int pageNumber) that returns the DocumentPage for the passed in pageNumber. Now the idea is to create a wrapper-class for the DocumentPaginator that is itself also of type DocumentPaginator. And now guys, what pattern is that? ;-) Doesn’t matter.

So we create a DocumentPaginator and let’s call it PageRangeDocumentPaginator. It encapsulates a DocumentPaginator and can return a specific (page)range of the encapsulated DocumentPaginator. Therefore the constructor takes two parameters: a DocumentPaginator to encapsulate and a PageRange-object that contains PageFrom and PageTo-Properties, both of type int. The PageRange-structure exists in the Namespace System.Windows.Controls.

The PageRangeDocumentPaginator-class is listed below. In the constructor the passed in DocumentPaginator is stored in the _paginator-field. The pageRange-values are stored in the fields _startIndex and _endIndex. As the PageRange starts with 1, we substract 1 to get the zero-based index. In the final line of the constructor the _endIndex is adjusted. If the user enters a higher pageNumber than the Document contains, _endIndex will point to the index of the last page.

Now look at the override of the GetPage-Method. There gets just the GetPage-Method of the encapsulated DocumentPaginator called. But the _startIndex is regarded. Now look at the PageCount-Property. It uses the _startIndex and _endIndex to calculate the pageNumbers. IsPageCountValid always returns true and the Properties PageSize and Source simply pass the responsibility to the underlying DocumentPaginator. That’s it. Now look how to use the class in the PrintButtonClick-Eventhandler.

/// <summary>
/// Encapsulates a DocumentPaginator and allows
/// to paginate just some specific pages (a "PageRange")
/// of the encapsulated DocumentPaginator
///  (c) Thomas Claudius Huber 2010
///      http://www.thomasclaudiushuber.com
/// </summary>
public class PageRangeDocumentPaginator : DocumentPaginator
{
  private int _startIndex;
  private int _endIndex;
  private DocumentPaginator _paginator;
  public PageRangeDocumentPaginator(
    DocumentPaginator paginator,
    PageRange pageRange)
  {
    _startIndex = pageRange.PageFrom - 1;
    _endIndex = pageRange.PageTo - 1;
    _paginator = paginator;

    // Adjust the _endIndex
    _endIndex = Math.Min(_endIndex, _paginator.PageCount - 1);
  }
  public override DocumentPage GetPage(int pageNumber)
  {
    // Just return the page from the original
    // paginator by using the "startIndex"
    return _paginator.GetPage(pageNumber + _startIndex);
  }

  public override bool IsPageCountValid
  {
    get { return true; }
  }

  public override int PageCount
  {
    get
    {
      if (_startIndex > _paginator.PageCount - 1)
        return 0;
      if (_startIndex > _endIndex)
        return 0;

      return _endIndex - _startIndex + 1;
    }
  }

  public override Size PageSize
  {
    get{return _paginator.PageSize;}
    set{_paginator.PageSize = value;}
  }

  public override IDocumentPaginatorSource Source
  {
    get { return _paginator.Source; }
  }
}

The PrintButtonClick-Eventhandler just needs a little if-statement. The PrintDialog has a Property called PageRangeSelection of Type PageRangeSelection (Enum). The PageRangeSelection-Enum contains the values AllPages and UserPages. When the User has entered a PageRange, that Property would have the value UserPages. In that case I use the PageRangeDocumentPaginator-class and pass in the DocumentPaginator of the FixedDocument and the PageRange from the PrintDialog. If the PageRangeSelection-Property contains not the value UserPages, we print all pages as we’ve already done in the problem-scenario. So the code looks like this:

void PrintButtonClick(object sender, RoutedEventArgs e)
{
  var dlg = new PrintDialog();

  // Allow the user to select a PageRange
  dlg.UserPageRangeEnabled = true;

  if (dlg.ShowDialog() == true)
  {
    DocumentPaginator paginator =
      _fixedDocument.DocumentPaginator;

   if (dlg.PageRangeSelection == PageRangeSelection.UserPages)
   {
     paginator = new PageRangeDocumentPaginator(
                      _fixedDocument.DocumentPaginator,
                      dlg.PageRange);
   }

    dlg.PrintDocument(paginator, "Yes, it works");
  }
}

When the user has selected a PageRange the PageRangeDocumentPaginator is used to generate the pages for the output. When I test the code with a PageRange of 2-3 as in the problem-section, I now retrieve the expected output of the two pages 2 and 3, as my “printed” PDF shows:

image

That’s it. Enjoy the code and download the solution here. And don’t forget to kick this post for me:

[Download Thomas PrintingProject]

kick it on DotNetKicks.com

Cheers Thomas

PS: As time and my sparetime is limited – I’m writing on my Silverlight 4.0 book and an update of my WPF book in my sparetime – I can’t give any free support for the code. Use it or not. But feel free to contact me for any suggestions via:

http://www.thomasclaudiushuber.com/contact.php

Hey Thomas, what’s coming up next?

Saturday, October 31st, 2009

I’ll give you just a short information of what is coming up next and what I did the last months. Let’s start with the things coming up…

… what’s coming up next:

  • WebTech-Conference – 16th November, Karlsruhe/Germany
    Another talk about datadriven Silverlight-Applications. Meet me at this conference for discussions about WPF, Silverlight, .NET in general, my books and other topics. Find more about the WebTech-conference on webtech
  • Update of the WPF-book to .NET 4.0 and Visual Studio 2010
    The WPF-book was written about .NET 3.5. Next year .NET 4.0 will be released. There are many new things introduced in WPF. The DataGrid- and DatePicker-Control, VisualStateManager, Animation Easing Functions, Layout Rounding and so on. I’m working on an update of the book that will be released next year shortly after the German Visual Studio Release.
  • Writing a german book about Silverlight 4
    Currently I’m working hard on my book about Silverlight 4. I’ve already written about 300 pages. The book will be released next year shortly after the Silverlight 4 release. There are no comments on the Silverlight 4 release, but at PDC in mid-November there’s a session about the Silverlight-Roadmap. Then we’ll know more. So stay tuned. Find more about the upcoming Silverlight-Book on the new silverlight-category on my homepage

… what I did the last months:

  • Silverlight-Articles
    I’ve written six articles about Silverlight for the German dotnet-magazine. Download the articles beside others on www.thomasclaudiushuber.com/articles.php.
  • PrioConference – 28th October, Munich/Germany
    I had a session about datadriven Silverlight-Applications. Find the Details on the new talks-category on my homepage.

So stay tuned. If you’ve any questions, leave a comment or write me an email via the contact-form on my homepage.

Thomas

WPF-Book on top in C#-Category

Thursday, August 27th, 2009

Even if it was maybe just for one hour, I’d like to say “Thank you” to all my readers for pushing the book up to the first place in the C#-Category on amazon.de.

Cheers Thomas 

image

WPF "Advanced Layout"-Session at BASTA

Saturday, February 21st, 2009

Next week you can meet me at the BASTA – a German Conference about .NET, Visual Studio & more. I’ll give a presentation about Layout-functionality in WPF on Tuesday at 13.30 o’clock. After the presentation you can meet me (on Tuesday only) and other "Trivadians" (the whole week) at the "Trivadis"-stand.

I’m looking forward to see you there. :-)

The Lottery-Console-Application used at the last WPF-Event @ Microsoft Usergroup Switzerland

Monday, August 25th, 2008

Last week we had a great WPF-afterwork-event at Microsoft Usergroup Switzerland (MSUGS) sponsored by Trivadis. I gave a deep-dive session about developing custom controls using WPF with many of it’s features like Dependency Properties, Commands, Routed Events, PART-Elements, Theme-Styles and so on.

At the end of the session a copy of my German WPF-book was drawn. We made a small lottery, but not a normal one. As all attendees were .NET-developers, everyone trusted in .NETs Random-class, so why don’t do it just in code?! We’ve written life a small console-application that did the job for us. As some people asked for the code (of course only the loosers and not the winner of the book ;-) ), here it is:

static void Main(string[] args)
{
  Console.WriteLine();
  Console.WriteLine("  --- MSUGS- WPF-Book Lottery");
  Console.WriteLine("  Enter names and a dot (\".\")"
                  + " when names are complete");
  Console.WriteLine();

  List<string> names = new List<string>();
  Console.Write(">");
  string name = Console.ReadLine().Trim();

  while (!name.Equals("."))
  {
    names.Add(name);
    Console.Write(">");
    name = Console.ReadLine().Trim();
  }

  Random random = new Random();
  int winnerIndex = random.Next(names.Count);

  string winner = names[winnerIndex];

  Console.WriteLine();
  Console.WriteLine("Starting lottery...");

  Thread.Sleep(3000);

  Console.Write("And the winner is");

  for (int i = 0; i < 10; i++)
  {
    Thread.Sleep(1000);
    Console.Write(".");
  }
  Console.WriteLine();
  Console.WriteLine();

  Console.WriteLine(winner);

  Console.ReadLine();
}

The Console-Application looks like this:

image

The lucky winner at the MSUGS-event was Stefan, he was at index zero in the names-Collection. Congratulations!

st_msugs_080820

Thanks to MSUGS for the great organization and to all developers who attended in the session. I hope you enjoyed it.

WPF-book is now available in stores, maybe you win a free one @MSUGS

Monday, June 30th, 2008

Since last week my German WPF-book is available in stores. You find more details about the book and some snippets of chapter 1 and chapter 14 on Galileo Computing. You can order the book on the Galileo Comuting-Website or on amazon.de and other stores.

For any questions about the book, write a comment to this post or use the contact-form of my homepage. If you’ve already got the book, I’m looking forward to your feedback.

What’s going on next:

Free MSUGS-Event about developing Custom Controls with the chance to win a WPF-book:
On Wednesday, 20th August, you can visit a free event in cooperation with the Microsoft User Group Switzerland (MSUGS) about developing Custom Controls with WPF. The event will be in Zurich @Trivadis (Europastrasse 5). You find more details about the event here. At the end of this event, you can win one WPF-Book for free.

WPF-Course @Trivadis:
If you want to know more things about WPF-Programming, take a look at the 3-day WPF-course at Trivadis, which you find here. If you take this course, you’ll get a WPF-book, the Trivadis course-material, and everything you need to become a rich & famous WPF-Programmer. ;-)

DataAccess in the time of LINQ:
Christoph Pletz and I are working on a TechnoCircle – a one day event you can visit in the second half of this year @Trivadis – about DataAccess in the time of LINQ. This TechnoCircle does not only show you how LINQ works, it shows how to implement a Data Access Layer in the time of LINQ in a Three-Layer-Architecture. It also discusses the usage of LINQ to SQL vs. Entity Framework vs. DataSets etc. As soon as you can register for the TechnoCircle, you’ll find more infos on the Trivadis-website and of course here on my blog…

Print of WPF-book will start next week

Saturday, May 31st, 2008

As I promised in my last post, here are some infos about my nearly finished book project:

Last weekend I made checks on the first galley proof of my german WPF-book. Yesterday I got the second galley proof, the corrected one. The second galley proof I’ve checked yesterday evening and today. The book will have about 1125 pages filled up with pure Windows Presentation Foundation and will be printed at the end of next week.

Last week I saw that the book is already listed under the WPF-books on WindowsClient.NET. Who ever linked it up, thanks a lot for doing so:
>> http://windowsclient.net/community/books.aspx

As the corrections are made and the book will be printed next week, the upcoming weekend will be the first totally free weekend for me since one year. Two weeks ago I got a red card in a soccer match, so I’m not allowed to play the last game. So next weekend is really totally free, no soccer game and no book-writing. :-)

So what should I do this upcoming weekend? I could start writing another WPF- or Silverlight-article. But no, on that first free weekend for such a long time I won’t do that. I tell you what I’m going to do, if the weather won’t be totally bad:

About one month ago I bought a new bike (on the picture below), so I’ll test it on a tour with my family next weekend. There are several mountains and single trails directly around our home, where you can jump and ride with a lot of fun. As I know there are also many bikers at Trivadis (the company I’m working for), maybe I’ll meet some of them in a race down the hills through the great black forest

bikingThomas

Got the MCTS: .NET Framework 3.5, Windows Presentation Foundation

Sunday, May 18th, 2008

Last Thursday I took the exam for the Microsoft Certified Technology Specialist .NET Framework 3.5, Windows Presentation Foundation. The exam is brand new and covers a wide spectrum of WPF.

Im not sure, if asking Multiple-choice-questions is a good thing for testing the knowledge of programmers, but hey, the exam was a good test for my German WPF-book. (I didn’t have the book with me, but it’s still in my head. Like a branding :-) ).

After every question I read, I thought, if the answer of the question can be found in my book. And I’m really glad to say that, with some exceptions to specific deployment questions, everything can be found in my book. So if you know all contents and details of my book well, you won’t have any problems to pass this exam. So with the book still in my head I did it and earned my fourth MCTS:

 MCTS_Logo

By the way, I’ve finished the manuscript for my wpf book in time. Since end of April the correctors give their best and I’m sure the book will be in stores in June 2008, according to plan. Find more infos about the book-process during the next weeks on this blog.

UIAutomation to open ComboBox from Code

Sunday, May 18th, 2008

In WPF there’s an Automation Framework called UIAutomation. This Framework can be used to control UIElements from code. This can be useful for different scenarios:

  • Provide the user additional help
  • Control a programm by another programm
  • Test applications
  • Execute a user-action from code

The Automation Frameowork isn’t limited to WPF. You can also control Win32-Applications.

In WPF for every FrameworkElement you find a class named like [TheElementsName]AutomationPeer. E.g. for the Button-class there’s a ButtonAutomationPeer-class, for ComboBox there’s a ComboBoxAutomationPeer-class…

Such AutomationPeer-Classes support different Patterns. E.g. the ComboBoxAutomationPeer-class supports the ExpandCollapse-Pattern to expand and collapse the ComboBox. You do this with the following snippet:

ComboBoxAutomationPeer peer =
  new ComboBoxAutomationPeer(yourComboBox);
IExpandCollapseProvider provider =
  (IExpandCollapseProvider)
  peer.GetPattern(PatternInterface.ExpandCollapse);
provider.Expand();

There’s much more you can do with UIAutomation, which is part of my German WPF-book (Chapter 19).