Yesterday, on Krakowska Grupa Deweloperów .NET, I gave a presentation, together with my friend Arkadiusz Świerczek, on latest Microsoft .NET Framework 3.5 SP1 WPF stuff and WPF Tips & Trick.
We didn't have enough time to cover all the goddies we've prepared, but we managed to introduce some basics around WPF and present WPF effects in pixel shader. Besides, we've presented how to write multi-language, runtime bound UI, skins and a rapid introduction to attached behaviors.
The presentation together with full sources can be downloaded from here. Enjoy!
Thursday, December 18, 2008
Saturday, November 29, 2008
patterns & practices: Composite WPF and Silverlight Drop 6
It's been couple of days since I started playing with Prism V2 Drop 6 (You can download it from here). Of course I've been using CompositeWPF aka Prism V1 for a longer time, and I must admin it's an excellent framework, but I wanted to see it's new Silverlight part. Here's what I've found so far.
In general, drop 6 seems working just fine. It contains the following features known from the WPF part:
As I previously said, everything is working fine. One thing disturbs me, however. On the very first version of Prism, I was able to use ordinary classes as views, the view was then defined as a data template. So I could have written something like that:
In this example, NavigationItemPresenter represents my custom button. However, there is no explicitly given view - the view is defined via data template. Unfortunately, from unknown reasons, this doesn't work in Silverlight. I receive NullPointerException. After "investigation" it turned out that internally, the view is casted to... DependencyObject!!! Why is that?! I don't known. I even tried to extend the DependencyObject class (yes, it's possible despite the fact many people say it's not), but I got other exceptions. To sum up, I use this release in my small project (small page for the product I'm currently working on, I'll post about it as soon as it's finished), but it's a pity that the cool approach with views defined using data templates doesn't work so far. Highly recommended.
In general, drop 6 seems working just fine. It contains the following features known from the WPF part:
- modularity
- event broker
- regions
As I previously said, everything is working fine. One thing disturbs me, however. On the very first version of Prism, I was able to use ordinary classes as views, the view was then defined as a data template. So I could have written something like that:
47
48 var downloadItemPresenter = m_Container.Resolve<NavigationItemPresenter>();
49 downloadItemPresenter.Text = "Download";
50
51 m_RegionManager.Regions[RegionNames.NavigationPanel].Add(downloadItemPresenter);
In this example, NavigationItemPresenter represents my custom button. However, there is no explicitly given view - the view is defined via data template. Unfortunately, from unknown reasons, this doesn't work in Silverlight. I receive NullPointerException. After "investigation" it turned out that internally, the view is casted to... DependencyObject!!! Why is that?! I don't known. I even tried to extend the DependencyObject class (yes, it's possible despite the fact many people say it's not), but I got other exceptions. To sum up, I use this release in my small project (small page for the product I'm currently working on, I'll post about it as soon as it's finished), but it's a pity that the cool approach with views defined using data templates doesn't work so far. Highly recommended.
Sunday, November 16, 2008
CLR Hosting Samples
Recently, while digging around my disk, I found two interesting samples concerning hosting Common Language Runtime in a native process. The first one actually shows some absolute basics. It comprises 3 demos showing how to host a CLR inside a C++ console application and how to call a managed code from C++, without using COM interoperability of course. If you are interested in this topic, I recommend you read very good stuff here. Besides, if you understand polish a little, familiarize yourself with my two articles. You will find links in My Articles section on the right.
The second sample is much more advanced, and unfortunately, there is no explanation how it works... This sample, called Deadlock Detector, let's you detect and break deadlock chains that occur inside .NET application. You can grab the bits from here. How can you see the sample working? Go to debug dir, run cmd and issue the following command: DeadlockDetector.exe DedlockedWindowsApplication.exe
You will see a WinForms application with two buttons: Deadlock and Work. The work button represents a real work that an application can perform. The deadlock button, on the other hand, represents a functionality with a bug - when run, it causes a deadlock. If you run this application without the Deadlock Detector host and hit the Deadlock button, all you can do is kill the app. However, if you run it through the Deadlock Detector, the host will print info about the deadlock and automatically kill one of the threads involved in the deadlock chain. Afterwords, the application will work normally. Cool, huh?
The second sample is much more advanced, and unfortunately, there is no explanation how it works... This sample, called Deadlock Detector, let's you detect and break deadlock chains that occur inside .NET application. You can grab the bits from here. How can you see the sample working? Go to debug dir, run cmd and issue the following command: DeadlockDetector.exe DedlockedWindowsApplication.exe
You will see a WinForms application with two buttons: Deadlock and Work. The work button represents a real work that an application can perform. The deadlock button, on the other hand, represents a functionality with a bug - when run, it causes a deadlock. If you run this application without the Deadlock Detector host and hit the Deadlock button, all you can do is kill the app. However, if you run it through the Deadlock Detector, the host will print info about the deadlock and automatically kill one of the threads involved in the deadlock chain. Afterwords, the application will work normally. Cool, huh?
Monday, November 10, 2008
WPF Wizard Control - Part I
Writing a custom wizard control (or simply a control of any kind) in many widely used GUI toolkits is usually a challenging task. But it turns out that doing such a control in WPF is rather easy. In this post, I'm going to explain how to create stylable, simple wizard that looks like this:
I recommend briefly examining attached source code before reading the post because the code is not short enough to be pasted on a blog. Still reading "pure" text without the code is far from being nice :)
As you probably know, WPF defines so called look less controls. This means the look and feel of the user controls is completely separated from its behavior. So firstly, I'll go through the wizard's behavior, and at the end I'll explain wizard's style in a few sentences. For now let's only assume that the wizard has navigation buttons such as Next, Previous, Finish, etc., and three places for content: wizard's header, left (side) header and of course a place for displaying main content. Note that I'm not defining yet where these pieces are going to be displayed, for now I only assume they exist somewhere.
The first decision I had to take was the class I needed to inherit from. The options were UserControl or a Control. Because I wanted to give the wizard some styling capabilities (via ComponentResourceKey) and also I wanted it to look more "professional" I decided to inherit from a Control class. There's yet another factor that actually convinced me no to using UserControl. UserControl directly inherits from a ContentControl, and the wizard itself does not have content of any kind! Wizard's content is provided by means of wizard pages and the wizard should display one page at a time. Precisely, wizard will "know" which page it should display (i.e. which page is the current one) and the wizard's template will contain ContentControl that will be databound to the main content of the current page. Of course the same approach will be used for the headers.
As you may have already guessed, single wizard page is represented by WizardPage class. Because it indeed has a content, it directly inherits from ContentControl. And because single WizardPage may provide optional header and side header, it has corresponding dependency properties of type object. Besides, this class defines some other properties like CanXXX which indicate if XXX navigation button is enabled for the page, and PageClose along with PageShow events that are raised whenever a page is closed or shown. As outlined above, the Wizard class contains a collection of WizardPage class.
The Wizard class contains two important dependency properties - ActivePage and ActivePageIndex. I hope their names are self descriptive. Not surprisingly, these two properties depend on each other, i.e. if I change ActivePageIndex, I expect ActivePage will automatically get updated, and vice versa. Moreover, I don't want to receive an error if I accidentally set inappropriate value for these properties. All this can be achieved using change and coerce callbacks. Here's the code:
OnActivePageChanged callback is especially important, because beside updating ActivePageIndex, it performs two other things. Firstly, it raises two events on a WizardPage class - it raises PageClose event on a page that is about to be replaced, then the page gets replaced and PageShow event is raised on a new page. And secondly, it checks if the current page is first or last in the wizard and enables or disables Next/Previous buttons accordingly.
Wizard's look & feel is defined in Themes\Generic.xaml using simple grid layout. The most important part of the control's template is how actually content of wizard's active page gets displayed in the wizard. This is accomplished using content placeholders in form of ContentControl. There is one problem with this design, however. All wizard's pages except the active one are NOT part of the logical tree as they are simply not displayed. And if the active page gets replaced, it is automatically removed from the visual tree. This implies two things. The first one is that the page's DataContext propertyis not propagated to the parent, i.e. if you put an instance of some class in the window's DataContext and you bind controls inside pages to this instance, this won't work (yes, I'm talking about PresentationModel pattern). The second thing is that you cannot bind controls with each other. Hopefully, there is an easy solution to overcome the first problem:
The second one is still unsolved, but because PresentationModel does work with the wizard, it's not a big deal (Update: to see how to solve these problems, see the second post).
You can download full sample from my Code Gallery.
Have fun!
I recommend briefly examining attached source code before reading the post because the code is not short enough to be pasted on a blog. Still reading "pure" text without the code is far from being nice :)
As you probably know, WPF defines so called look less controls. This means the look and feel of the user controls is completely separated from its behavior. So firstly, I'll go through the wizard's behavior, and at the end I'll explain wizard's style in a few sentences. For now let's only assume that the wizard has navigation buttons such as Next, Previous, Finish, etc., and three places for content: wizard's header, left (side) header and of course a place for displaying main content. Note that I'm not defining yet where these pieces are going to be displayed, for now I only assume they exist somewhere.
The first decision I had to take was the class I needed to inherit from. The options were UserControl or a Control. Because I wanted to give the wizard some styling capabilities (via ComponentResourceKey) and also I wanted it to look more "professional" I decided to inherit from a Control class. There's yet another factor that actually convinced me no to using UserControl. UserControl directly inherits from a ContentControl, and the wizard itself does not have content of any kind! Wizard's content is provided by means of wizard pages and the wizard should display one page at a time. Precisely, wizard will "know" which page it should display (i.e. which page is the current one) and the wizard's template will contain ContentControl that will be databound to the main content of the current page. Of course the same approach will be used for the headers.
As you may have already guessed, single wizard page is represented by WizardPage class. Because it indeed has a content, it directly inherits from ContentControl. And because single WizardPage may provide optional header and side header, it has corresponding dependency properties of type object. Besides, this class defines some other properties like CanXXX which indicate if XXX navigation button is enabled for the page, and PageClose along with PageShow events that are raised whenever a page is closed or shown. As outlined above, the Wizard class contains a collection of WizardPage class.
The Wizard class contains two important dependency properties - ActivePage and ActivePageIndex. I hope their names are self descriptive. Not surprisingly, these two properties depend on each other, i.e. if I change ActivePageIndex, I expect ActivePage will automatically get updated, and vice versa. Moreover, I don't want to receive an error if I accidentally set inappropriate value for these properties. All this can be achieved using change and coerce callbacks. Here's the code:
225
226 private static void OnActivePageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
227 {
228 Wizard wizard = (Wizard)d;
229 int index = (int)e.NewValue;
230 int oldIndex = (int)e.OldValue;
231
232 if (index != -1 && index != oldIndex)
233 wizard.ActivePage = wizard.WizardPages[index];
234 else if (index == -1)
235 wizard.ActivePage = null;
236 }
237
238 private static object CoerceActivePageIndex(DependencyObject d, object value)
239 {
240 Wizard wizard = (Wizard)d;
241 int index = (int)value;
242
243 if (index >= wizard.WizardPages.Count)
244 return wizard.WizardPages.Count - 1;
245
246 if (index >= 0 && index < wizard.WizardPages.Count)
247 return index;
248
249 if (index < 0 && wizard.WizardPages.Count > 0)
250 return 0;
251
252 return -1;
253 }
254
255 private static void OnActivePageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
256 {
257 Wizard wizard = (Wizard)d;
258 WizardPage page = (WizardPage)e.NewValue;
259 WizardPage oldPage = (WizardPage)e.OldValue;
260
261 if (page != null && oldPage != page)
262 {
263 // Raise event
264 if (oldPage != null)
265 oldPage.OnPageClose();
266
267 // update the index
268 int index = wizard.WizardPages.IndexOf(page);
269 wizard.ActivePageIndex = index;
270
271 // Set boundary values for navigation buttons
272 if (index == 0)
273 {
274 wizard.ActivePage.CanNavigatePrevious = false;
275 if (wizard.WizardPages.Count == 1)
276 wizard.ActivePage.CanNavigateNext = false;
277 }
278 else if (index == wizard.WizardPages.Count - 1)
279 wizard.ActivePage.CanNavigateNext = false;
280
281 // After page is up and runnig, rais event
282 page.OnPageShow();
283 }
284 else if (page == null)
285 {
286 // Raise event
287 if (oldPage != null)
288 oldPage.OnPageClose();
289
290 wizard.ActivePageIndex = -1;
291 }
292 }
293
294 private static object CoerceActivePage(DependencyObject d, object value)
295 {
296 Wizard wizard = (Wizard)d;
297 WizardPage page = (WizardPage)value;
298
299 int index = wizard.WizardPages.IndexOf(page);
300
301 // Given page does not exist in the internal collection
302 if (index == -1)
303 {
304 if (wizard.WizardPages.Count > 0)
305 return wizard.WizardPages[0];
306
307 return null;
308 }
309
310 return page;
311 }
OnActivePageChanged callback is especially important, because beside updating ActivePageIndex, it performs two other things. Firstly, it raises two events on a WizardPage class - it raises PageClose event on a page that is about to be replaced, then the page gets replaced and PageShow event is raised on a new page. And secondly, it checks if the current page is first or last in the wizard and enables or disables Next/Previous buttons accordingly.
Wizard's look & feel is defined in Themes\Generic.xaml using simple grid layout. The most important part of the control's template is how actually content of wizard's active page gets displayed in the wizard. This is accomplished using content placeholders in form of ContentControl. There is one problem with this design, however. All wizard's pages except the active one are NOT part of the logical tree as they are simply not displayed. And if the active page gets replaced, it is automatically removed from the visual tree. This implies two things. The first one is that the page's DataContext propertyis not propagated to the parent, i.e. if you put an instance of some class in the window's DataContext and you bind controls inside pages to this instance, this won't work (yes, I'm talking about PresentationModel pattern). The second thing is that you cannot bind controls with each other. Hopefully, there is an easy solution to overcome the first problem:
44
45 ///
46 /// Returns a collection of wizard's pages.
47 ///
48 public WizardPagesCollection WizardPages
49 {
50 get { return m_WizardPages; }
51 set
52 {
53 m_WizardPages = value;
54 m_WizardPages.CollectionChanged += OnWizardPagesChanged;
55 }
56 }
142
143 private void OnWizardPagesChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
144 {
145 // This code glues all wizard's pages to wizard's DataContext. This is done due to the fact that when pages are switched, the
146 // page that is hidden looses its data context.
147 foreach (var page in WizardPages)
148 {
149 var binding = new Binding("DataContext") { Source = this };
150 BindingOperations.SetBinding(page, DataContextProperty, binding);
151 }
152 }
The second one is still unsolved, but because PresentationModel does work with the wizard, it's not a big deal (Update: to see how to solve these problems, see the second post).
You can download full sample from my Code Gallery.
Have fun!
Sunday, November 2, 2008
How to paste source code from Visual Studio into a blog ?
Yes, it's true. This is my first blog post on Blogger :) But if You think it's yet another dummy post, I'll surprise You. In this post, I'm going to share single thought about pasting C# source code directly from Visual Studio 2008 as it is my primary IDE. Let's begin, shall we ? ;]
OK. So U want to share code on a blog... This is actually typical case. Of course you want your code to have proper indentation, and probably syntax coloring. There's excellent piece of a free software that can help U with this - CopySourceAsHtml (CSAH) plugin for VS 2008. U can find it here. It's usage is as simple as selecting desired code, hitting right mouse click and selecting Copy As HTML... And this is how a typical C# hello world application looks like using formatting from this tool:
There's a one problem, however. This tool does not work with XAML or more generally with any XML code at all! Hope support will be added ASAP.
Enjoy!
OK. So U want to share code on a blog... This is actually typical case. Of course you want your code to have proper indentation, and probably syntax coloring. There's excellent piece of a free software that can help U with this - CopySourceAsHtml (CSAH) plugin for VS 2008. U can find it here. It's usage is as simple as selecting desired code, hitting right mouse click and selecting Copy As HTML... And this is how a typical C# hello world application looks like using formatting from this tool:
20 ///
21 /// Some remarks :)
22 ///
23 public class SomeClass
24 {
25 public const string MyString = "I'm a constant!";
26
27 private static void Main(string[] args)
28 {
29 Console.WriteLine(MyString);
30 }
31 }
There's a one problem, however. This tool does not work with XAML or more generally with any XML code at all! Hope support will be added ASAP.
Enjoy!
Subscribe to:
Posts (Atom)