... a journey through WPF, MVVM and .NET4 RSS 2.0
# Monday, August 13, 2007

If you right click on "References" in a VS2008 project you will find only two options now - "Add Reference" and "Add Service Reference".  The first is for local assemblies, and the second generates WCF-compatible proxies through SVCUTIL.EXE.  This happens to be one of the most obviously changed things in Orcas - the dialog presented is a more professional version than what was supplied with the original WCF CTP for VS.2005:

The "Discover" button above can locate IIS-hosted web services (not Self Hosted however) and it now shows operations directly which is pretty cool.  The best part is the "Advanced" button though.  Clicking that gives you:

Here you can control all the details of SVCUTIL.EXE -- how to reuse types, whether to generate public/private types, whether to genrate lower-level message contracts (giving complete control over the SOAP structure), and whether to generate asynchronous methods (ala the original web services references in .NET 2.0).

The bottom section - "Compatibility" allows you to generate a web service proxy using that original WS technology.  Clicking this will yield the traditional dialog you are probably used to:

So, if you were confused by the lack of a "Add Web Reference" in Orcas, fear no more - it's still there just a little harder to get to!

You might be asking - "Why would I want to generate one of those?  Why not just use WCF?"  Well, we have to keep in mind that not all our clients want to move to WCF just yet (as much as we want them to, there is a cost in deployment), and second, WCF isn't supported on pre-XP platforms.  There are still a lot of Windows 2000 systems out there!  For those clients, we have no choice but to use legacy web service proxies.

Monday, August 13, 2007 2:58:09 PM (Central Daylight Time, UTC-05:00)  #    Comments [0] -
.NET
# Monday, July 30, 2007
Microsoft apparently didn't resign all the tools in the SDK supplied with Beta 2 of Visual Studio 2008.  This is actually documented in the readme that UISpy has this issue, which of course, I didn't read..
 
SVCUtil.exe also has this problem and it causes any proxy-generation from VS.NET 2008 to fail (as well as killing the client tester process which is spawned for WCF testing).  You'll know you've hit this error when the program crashes with a "System.IO.FileException" and indicates that it has failed strong-name validation.
 
It's easy enough to fix ..
 
1) Open a command prompt with full admin rights
2) CD to the C:\Program Files\Microsoft SDKs\Windows\V6.0a\bin directory
3) execute "SN -Vr svcutil.exe"
 
This turns off strong-name validation for svcutil.exe.
 
Monday, July 30, 2007 5:20:15 PM (Central Daylight Time, UTC-05:00)  #    Comments [0] -
.NET
# Monday, July 16, 2007

I've been playing a bit with VS.NET '08 June CTP lately and noticing several nice improvements - the Cider WPF add-in especially seems to have better integration with the code window.  For example, double clicking on an element now creates the code-behind handler (finally!).

The layout support is much better as well - you finally get the drag handles and positioning lines.

 

The property sheet seems a bit sketchy right now - I see how Blend has certainly influenced it (as the code apparently is coming from that product), but I find Blend to be easier to work with there.  No support for Data Providers either which is a bummer.

Bindings are still not as nice as Blend; manual addition seems to be the only way to do them at this point, however Intellisense is *much* better now.  There's also a nice zoom bar present which allows fine-detail work to be done when drawing graphical elements (such as Control Templates or even just 2D/3D shapes).

Overall, I'm seeing some good progress - here's hoping for more as the product matures!

Monday, July 16, 2007 1:26:30 PM (Central Daylight Time, UTC-05:00)  #    Comments [0] -
.NET | WPF
# Friday, July 13, 2007

Sales of the TSP++ products have steadily fallen over the past 5 years, so much so that I decided two years ago to release the 2.x product into the open-source community, and now I am doing the same for the server edition. 

The download is available here and requires a key to install it - use 

J35M-3KXo-q60T

which will let you install the full product.  Documentation and samples are all part of the image so have fun!

Friday, July 13, 2007 4:46:33 PM (Central Daylight Time, UTC-05:00)  #    Comments [0] -
Code | Tapi
# Tuesday, April 17, 2007
For those students who were in the London WPF class last week, I've posted the demos and labs/slides up on the website. You can get them using "dmstudent" as the id and the password mentioned in class from here: Demos and Labs. In the labs zip, open Coursebook and you can then open any of the slide links. If there are any questions, feel free to send them my way!
Tuesday, April 17, 2007 1:00:55 PM (Central Daylight Time, UTC-05:00)  #    Comments [0] -
WPF
# Wednesday, January 17, 2007

About a year ago, I blogged on using the .NET 2.0 facility SynchronizationContext to create thread-aware components which could be hosted and would "do the right thing" for callbacks. Here's the Link to that post.

Recently, I got an email from a reader who wanted to use that paradigm, but wanted to be able to suspend the operation for some period of time and then resume it later on. He asked if there was an easy way to modify the sample I presented, and it turns out that there is.

It essentially involves three steps:

1. In the AsyncStateData structure, add a ManualResetEvent object. This will be used to trigger the pause/resume behavior. It must be initially set as signaled.

2.
In the actual asynchronous operation loop, add the event into the loop condition by calling event.WaitOne(). Make sure you have released any locks and the code can safely be halted at that point in the logic otherwise you may create deadlock scenarios and other difficult debugging issues.

3.
Add a Pause and Continue method into the class which signals and resets the event.

Modifying my previous code example, here's what I come up with:

Step 1: Add the event to AsyncStateDate

   1:  class AsyncStateData
   2:  {
   3:      private ManualResetEvent pauseEvent = new ManualResetEvent(true);
   4:      ...
   5:  }

Step 2: Add event into the loop at a safe point

   1:  public partial class Calculator
   2:  {
   3:      private void InternalCalculatePi(int digits, AsyncStateData
   4:  asyncData)
   5:      {
   6:         int completedDigits = 0;
   7:         for (; !asyncData.canceled && pauseEvent.WaitOne(-1, true) &&
   8:  completedDigits < digits; completedDigits++)
   9:         {   ...  }
  10:      }
  11:   
  12:  ...
  13:  }

Step 3: Add a Pause and Continue API

   1:  public partial class Calculator
   2:  {
   3:      public void PauseAsync(object asyncTask)
   4:      {
   5:          AsyncStateData asyncData = asyncTask as AsyncStateData;
   6:          if (asyncData != null && asyncData.running == true)
   7:              asyncData.pauseEvent.Reset();
   8:      }
   9:   
   10:     public void ContinueAsync(object asyncTask)
   11:     {
  12:          AsyncStateData asyncData = asyncTask as AsyncStateData;
  13:          if (asyncData != null && asyncData.running == true)
  14:              asyncData.pauseEvent.Set();
  15:     }
  16:  ...
  17:  }


There are certainly other ways to do this as well, for example, create a dedicated Thread object instead of using an Async delegate and then call Suspend on the thread (and Resume to continue). That can be dangerous if you take locks while running your async operation so the ManualResetEvent is probably a better solution from that perspective (since you are blocking in a known location vs. just suspending the thread arbitrarily and potentially holding onto shared resources.
Wednesday, January 17, 2007 10:11:04 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | Code | Real World
According to the super villain quiz I am

Lex Luthor
A brilliant businessman on a quest for world domination and the self-proclaimed greatest criminal mind of our time!
Click here to take the Super Villain Personality Test
Wednesday, January 17, 2007 8:02:01 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -

One of the nifty new features of the WPF platform is the pluggable data providers.  It ships with two out of the box:

ObjectDataProvider: allows you to execute binding expressions against an object and it's methods
XmlDataProvider: loads an XML data source and makes it available as a binding source

Both of these derive from the abstract class System.Data.DataSourceProvider which implements the binding glue (INotifyPropertyChanged) needed for data binding.  A side note here is that you could write your own custom data provider if you needed to, although if the data is exposed through a .NET object, then the ObjectDataProvider is probably sufficient.

Using the providers is fairly easy -- let's say we have some XML data that looks like this:

<?xml version="1.0" encoding="utf-8"?>
<taxrecords>
 
<entry name="Opal Harrison" state="AL" income="$51,466.81" age="27" />
 
<entry name="Eugene Black" state="FL" income="$13,314.89" age="71" />
 
<entry name="Opal Chang" state="NC" income="$225,115.15" age="41" />
 
<entry name="Gary Waters" state="WI" income="$151,788.49" age="39" />
 
<entry name="Xavier Davis" state="AK" income="$136,344.97" age="66" />
 
<entry name="Stacy Harrison" state="TX" income="$122,432.82" age="32" />
</taxrecords>

The goal is to put this data into a ListBox - displaying the fields in the following format:

Name
State, Age, Income

We could clearly do all of this from procedural code -- create an XmlReader object, load the data and render each XmlNode into the listbox.  However, this is the 21st century and so we want to avoid coding as much as we can and utilize the underlying framework support instead!

We can get the data loaded into a collection source through the XmlDataProvider.  This is easily done in XAML:

<XmlDataProvider Source="largeXmlFile.xml" x:Key="xmlData" XPath="/taxrecords" />

This will look for the file "largeXmlFile.xml", create an XmlDocument and load the file into memory.  Notice we supply an XPath expression as part of this to indicate what we'd like the data provider to hand us as the collection itself.  In this case, we want to see everything under the node "taxrecords" which is the root of the document.  An interesting facet of this provider is that it performs it's work asynchronously -- you can see this behavior when you load very large XML files.  The UI will come up first, completely empty and then suddenly be populated with data.  The behavior can be adjusted through the IsAsynchronous property of the data provider.  Setting this to false will delay the display of the UI until the data is fully available.

Another interesting thing about this class is that we can define the XML data inline within the XAML document.  You do this with the x:XData tag:

<XmlDataProvider x:Key="xmlData" XPath="/taxrecords">
   <x:Data>
       <taxrecords>
         
<entry name="Opal Harrison" state="AL" income="$51,466.81" age="27" />
         
<entry name="Eugene Black" state="FL" income="$13,314.89" age="71" />
              ...

       </taxrecords>
  
</x:Data>
</XmlDataProvider>

The next step is to bind this data to a ListBox control - this is a normal Data Binding expression:

<ListBox Name="lb1" Margin="10" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource xmlData, XPath=entry}}">

Notice how we use a new property of the BindingExpression called XPath.  This property allows you to identify which element(s) you want to load from the XML data source.  It is specific to this data provider and allows for any XPath expression to be supplied.  This will succesfully load each of the "/taxrecord/entry" nodes into the ListBox, but the data itself will show up as a blank line.  This, of course, is because the data is really an XmlNode object which the ListBox has no idea how to display.  To fix this, we supply a DataTemplate to render our data: 

<ListBox.ItemTemplate>
   <
DataTemplate>
      <
StackPanel>
         <TextBlock FontWeight="Bold" Text="{Binding XPath=@name}" />
         <
StackPanel Orientation="Horizontal">
            <
TextBlock Text="{Binding XPath=@state}" />
            <
TextBlock Text=", " />
            <
TextBlock Text="{Binding XPath=@age}" />
            <
TextBlock Text=", " />
            <
TextBlock Text="{Binding XPath=@income}" />
         </
StackPanel>
      </
StackPanel>
   </
DataTemplate>
</
ListBox.ItemTemplate>

Again, we use the XPath property to define what piece of information we are binding to -- attributes of our entry in this case.  This template will give us the format we are looking for:

We can add sorting, filtering and grouping using the normal CollectionViewSource support.  Here is a XAML file which will present the above UI complete with sorting by the age element.  Notice how the XPath expression now moves to the CollectionView.  This is because the CollectionViewSource creates a ListCollectionView to manage the XML nodes because the data provider supports the IList interface.  The binding expression on the listbox is now simply a binding to the collection view.

<Window Title="AsyncDataBind" Height="300" Width="300"
 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 
xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Window.Resources>

  
<
XmlDataProvider Source="largeXmlFile.xml" IsAsynchronous="True"
                            
x:Key="xmlData" XPath="/taxrecords" />

  
<
CollectionViewSource x:Key="collView" Source="{Binding Source={StaticResource xmlData},XPath=entry}">
     
<
CollectionViewSource.SortDescriptions>
        
<
cm:SortDescription PropertyName="@age" Direction="Ascending" />
     
</
CollectionViewSource.SortDescriptions>
  
</
CollectionViewSource>

</
Window.Resources>

<
Grid>
  
<
Grid.RowDefinitions>
     
<
RowDefinition Height="*" />
     
<
RowDefinition Height="Auto" />
  
</
Grid.RowDefinitions>

   <ListBox Name="lb1" Margin="10" IsSynchronizedWithCurrentItem="True"
               
ItemsSource="{Binding Source={StaticResource collView}}">

     
<
ListBox.ItemTemplate>
        
<
DataTemplate>
           
<
StackPanel>
              
<
TextBlock FontWeight="Bold" Text="{Binding XPath=@name}" />
              
<
StackPanel Orientation="Horizontal">
                 
<
TextBlock Text="{Binding XPath=@state}" />
                 
<
TextBlock Text=", " />
                  
<
TextBlock Text="{Binding XPath=@age}" />
                 
<
TextBlock Text=", " />
                 
<
TextBlock Text="{Binding XPath=@income}" />
               
</
StackPanel>
            
</
StackPanel>
         
</
DataTemplate>
      
</
ListBox.ItemTemplate>

   
</
ListBox>

   <Button Grid.Row="1">
     
<
StackPanel Orientation="Horizontal">
        
<
TextBlock Text="{Binding ElementName=lb1, Path=Items.Count}" />
        
<
TextBlock Text=" Items" />
      
</
StackPanel>
   
</
Button>

</
Grid>
</
Window>

Data binding in WPF is extremely powerful -- I am constantly amazed at how much procedural code you can dump in favor of markup with creative bindings.  In the next post I'll talk a bit more about asynchronouus bindings outside of the two data providers.

Until then..

Wednesday, January 17, 2007 4:57:58 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | Code | WPF
# Friday, December 08, 2006

There's been a discussion going on within DevelopMentor for a couple weeks regarding concurrent GC and when it really applies.

The idea behind the concurrent collector is to do as much of the GC while the UI thread continues to process UI stuff and then only interrupt the application threads when memory is being shuffled around and fixups are occurring. This provides for more responsive UI applications at the expense of slower collections and a higher memory utilization.

The instructors who are involved with .NET were discussing this because of a discrepancy in various reliable sources - First, Maoni Stephens, the ultimate authority on all things .NET GC, stated in her blog entries that concurrent GC was the default behavior for the workstation version of GC (see http://blogs.msdn.com/maoni for more information on this).

This is well known, and now well documented in various places. However, Jeff Richter seems to say in his book "CLR via C#" that concurrent collections occur only on multiprocessor machines. Several other authors back this up (notably Stephen Pratschner in "Customizing the .NET Framework Common Language Runtime" and Joe Duffy in his "Professional .NET Framework 2.0" book; both are excellent btw).

So, we had some differing opinions from people in the "know". Our Effective .NET and Essential .NET courses were written around Maoni's blogs and so the diagram we presented showed concurrent collections even on single-processor machines since she didn't explicitly say it required multiple processors to turn it on. One of the guys noticed this and said "Wait! That's wrong!"

We tried to actually see the concurrent collection in action but it turns out that it's actually quite difficult to get this to happen because concurrent collections only occur on Gen2, which for a well-written application shouldn't occur that often. To add to the complexity, the CLR attempts to optimize this behavior - just because it can do the GC concurrently, it might not.  Finally, the thread which is used for this collection is actually created and destroy as necessary so it doesn't exist most of the time.

So, to settle the argument, Jason Whittington and I spent some time spelunking into the CLR this past week to see if we could spot the concurrent collection in action. With a little WinDBG and some symbols, I think we've put the question to rest once and for all (at least for us) :-).  If you scan the GC symbols in mscorwks.dll, you'll find a treasure trove of information; one of the things that caught my eye was this:

0:000> x mscorwks!WKS::gcheap::*
79f8c5dd mscorwks!WKS::GCHeap::Relocate = <no type information>
7a0d09d9 mscorwks!WKS::GCHeap::ValidateObjectMember = <no type information>
7a088e2a mscorwks!WKS::GCHeap::IsConcurrentGCInProgress = <no type information>
Disassembling that method showed me that it checks a flag in memory --
0:000> u mscorwks!WKS::GCHeap::IsConcurrentGCInProgress 
mscorwks!WKS::GCHeap::IsConcurrentGCInProgress:
7a088e2a a1701b387a      mov     eax,dword ptr [mscorwks!WKS::gc_heap::settings+0x10 (7a381b70)]
7a088e2f c3              ret
I tried putting a breakpoint at the end of the GC process and dumping that flag out when it was a Gen2 collection (the breakpoint itself stolen shamelessly from Maoni's MSDN article in November 2006):
0:000> bp mscorwks!WKS::GCHeap::RestartEE "j 
(dwo(mscorwks!WKS::GCHeap::GcCondemnedGeneration)==2)
'dd mscorwks!WKS::gc_heap::settings+0x10 L1';'g'"
But I didn't get much success seeing it set to "1" - I suspect that it requires a more complex application than I was using to cause the CLR to decide a concurrent collection is worth the effort. So I decided this was a dead end and started looking to see where the GC process determines that concurrent collections are allowed at all. I figured GCHeap::Initialize sounded like a good spot --
0:000> u mscorwks!WKS::GCHeap::Initialize
mscorwks!WKS::GCHeap::Initialize:
79ed6924 a14412387a      mov     eax,dword ptr [mscorwks!g_pConfig (7a381244)]
79ed6929 8b4058          mov     eax,dword ptr [eax+58h]
.....
79ed697b 51              push    ecx
79ed697c e823040000      call    mscorwks!WKS::gc_heap::initialize_gc (79ed6da4)
79ed6981 85c0            test    eax,eax
Going into that function yielded what I was looking for --
0:000> u mscorwks!WKS::gc_heap::initialize_gc
mscorwks!WKS::gc_heap::initialize_gc:
79ed6da4 56              push    esi
79ed6da5 e80cf1ffff      call    mscorwks!WKS::write_watch_api_supported (79ed5eb6)
79ed6daa 33f6            xor     esi,esi
...
79ed6dc6 c70564ce387a01000000 mov dword ptr [mscorwks!WKS::gc_heap::gc_can_use_concurrent (7a38ce64)],1
Looking at that particular memory location, I tried various configurations to make sure I had the right spot. First, I did a simple console app with no config file and dumped out the location on a multi-processor box:
0:000> dd mscorwks!WKS::gc_heap::gc_can_use_concurrent L1
7a38ce64  <b>00000001b>
Next, I set the application up in server mode (also on a multi-processor box):
<xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <gcServer enabled="true" />
  </runtime>
</configuration>
0:000> dd mscorwks!WKS::gc_heap::gc_can_use_concurrent L1
7a38ce64  <b>00000000b>
Showing that it was now off.. next I tried a VM session which emulates a single processor:
0:000> dd mscorwks!WKS::gc_heap::gc_can_use_concurrent L1
7a38ce64  <b>00000001b>

It appears that the CLR is capable of doing concurrent collections on a single processor! My final test was to try turning it off altogether via a configuration switch:

<xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <gcConcurrent enabled="false" />
  </runtime>
</configuration>
0:000> dd mscorwks!WKS::gc_heap::gc_can_use_concurrent L1
7a38ce64  <b>00000000b>

As a final note on this, Jason asked Maoni directly and her response was that concurrent GC does not depend on the number of processors - just as we are seeing above. So, apparently several primary sources are actually incorrect on this behavior. It just goes to show how complex the overall GC process really is -- simple in concept, but boy there are a lot of moving parts!
Friday, December 08, 2006 1:25:29 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | Debugging
I've updated ATAPI.NET in the samples page http://www.julmar.com/samples/atapinet.zip with several fixes and support for conferences, full transfers and phone support. I think almost everything is now wrapped - if you find any missing functions that you want/need ping me and I'll see what I can do.
Friday, December 08, 2006 12:11:22 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | Tapi
I'm a WPF Disciple
Search
Categories
Archive
<August 2007>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678
About the author/Disclaimer

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

© Copyright 2010
Mark Smith
Sign In
All Content © 2010, Mark Smith
DasBlog theme 'Business' created by Christoph De Baene (delarou)