Sunday, July 13, 2008
Wednesday, July 02, 2008
The riddle of the disappearing WPF databinding
I'm currently on a custom control that has a bunch of panels slaved to each other via databinding. And I ran into a bug where moving an element around would suddenly break the sync with the other panels. Nothing in the Output about data-binding failing, so i inspected it with Snoop to see that my data-binding had just up and gone away. So I tracked down the suspect code and monitored the data source with Mole as i stepped through and saw that the data-binding went away right after I set the dependency property.Yeah, not really magic at all. A quick look at the Xaml showed that I had left this particular binding as default (i.e. OneWay). And if you have a OneWay binding and manually set the dependency property, the binding gets overwritten and goes away. Switching the binding to Mode=TwoWay restored my sync.
Tuesday, July 01, 2008
WPF Custom Panel layout and Dependency Properties
Just a quick note I learned the hard way when creating custom panels in WPF: If your panel has dependency properties or attached properties on its children that affect measure and/or arrange, calling InvalidateMeasure or InvalidateArrange won't necessarily do the trick. For that matter, calling these methods isn't even necessary. Instead use the FrameworkPropertyMetadata Metadata class to set appropriate FrameworkPropertyMetadataOptions.So if you have a Dependency Property on your panel that affects the measure or arrange of its children, make sure it has FrameworkPropertyMetadataOptions.AffectsMeasure and/or FrameworkPropertyMetadataOptions.AffectsArrange set.
Similarily, if your panel has an attached property for its children, whose modification affects how that child is laid out, set FrameworkPropertyMetadataOptions.AffectsParentMeasure and/or FrameworkPropertyMetadataOptions.AffectsParentArrange.
Now layout and arrange are properly invalidated and called for you.
Wednesday, March 19, 2008
XP 64, IIS 6 and ASP.NET
My current dev machine is running XP 64, which is a first for me. In the default setup IIS was not installed, so I went through Add/Remove Programs and installed it, which gave me IIS 6. This in turn has several tabs for ASP.NET, but try as you might none of these are what actually turns on ASP.NET and you just end up with mysterious 404s on a application enabled directory that's configured just like the working ASP.NET on your other machine.Well, it turns out that ASP.NET (even though it shows up in the Properties tabs) is not installed by default and if you go to Web Service Extensions you won't see it there. So next, track down aspnet_regiis which is in the Framework directory and run
aspnet_regiis -iThen go back to IIS Manager -> Web Service Extensions where ASP.NET should now be an available extension. Enable it and finally ASP.NET works.
Tuesday, March 11, 2008
Sharing code between Silverlight and .NET
Currently, a Silverlight Class Library cannot be loaded by the server side project and vice versa. This despite there being very close parity in the BCL on either side. Now, I agree that sharing actual business logic between client and server is a bit of an edge case, but when it comes to data interchange, having a single codebase for you DTOs would be very useful.Luckily, with a bit of trickery, this can be accomplished, although it would be nice if Visual Studio could just do this for you. I've done this on two different projects, once creating DTOs that were then serialized using the JSON DataContract serializer and other other time using the normal XmlSerializer.
The basic trick is this: Two separate projects can point at the same source code files (and even the integrated source control providers will play along with this game). However, playing by Visual studio rules you can't just create two projects in the same directory because the wizards treats ProjectName == DirectoryName. Here's how you get around this:
- Create a new server side Class Library, say Server.Dto.
- Create a new Silverlight Class Library, say Silverlight.Dto.
- Clean out that default Class.cs and update both to have the same default namespace Foo.Dto. Your solution should look something like this:
- Now, right-click on Silverlight.Dto and choose Remove
- Close Visual Studio
- Rename the Silverlight.Dto/Properties directory to Silverlight.Dto/Silverlight.Properties
- Copy Silverlight.Properties and Silverlight.Dto.csproj to the Server.Dto directory
- Now, and this is the tricky bit, open Silverlight.Dto.csproj in some text-editor (notepad works, but don't try to use Visual studio for this) and change the line
<Compile Include="Properties\AssemblyInfo.cs" />
to<Compile Include="Silverlight.Properties\AssemblyInfo.cs" />
- Re-open your solution, right-click on the Solution in the Solution Explorer and choose Add -> Existing Project..., browse to Server.Dto and select Silverlight.Dto.csproj
- Add your first shared class FooDto.cs to Server.Dto (if you add it on the Silverlight side, you need to clean up a bunch of using statements).
- Select Silverlight.Dto and click the Show All Files button at the top of the panel. You should see FooDto.cs in Silverlight.Dto now
- Right-click FooDto.cs and choose Include in Project, like this:
- Voila, you now have two assemblies referencing the same code so that you can use the same code on both client and server sides. Just repeat the last couple of steps for every new class you want to share.
I know you could use a Web Service from within Silverlight and would automatically generate you the proxy on the client side. And I'd recommend that if your payload is dynamic. However, if your payload is generated occasionally by a server side program or periodic service, this methods lets you create Dto's, serialized in your favorite manner that can be consumed as static files with WebClient.
Labels: .net, c#, silverlight
Saturday, March 08, 2008
Epoch DateTime conversion Extension Methods
Interop with unix often requires dealing with Epoch or Unix time, or the number of seconds since January 1st, 1970 UTC. And if you throw java in the mix, then epoch becomes milliseconds, since they define System.currentTimeMillis() as the number milliseconds since the Epoch. Anyway, i figured, this was the perfect use of Extension methods. Well, almost... There's still the issue that getting a DateTime object from seconds requires a static method added to DateTime, which extension methods do not currently support. This means that instead ofDateTime utcDateTime = DateTime.FromEpochSeconds(seconds)
DateTime utcDateTime = DateTimeEx.FromEpochSeconds(seconds)
DateTime utcDateTime = 1205003848.DateTimeFromEpochSeconds();
The one thing to be aware of with all these helpers is that it always deals with UTC time, i.e. the DateTime that you convert to epoch time needs to have a DateTimeKind that is not Unspecified. Conversely, the DateTime you get back is UTC and if you want to deal with it with localtime, you need to call ToLocalTime() on it first.
Anyway, here's the class:
using System; namespace Droog.DateTime { public static class DateTimeEx { public static DateTime FromEpochMilliseconds(long milliseconds) { return new DateTime(1970, 1, 1,0,0,0,DateTimeKind.Utc).AddMilliseconds(milliseconds); } public static DateTime FromEpochSeconds(int seconds) { return FromEpochMilliseconds((long)seconds * 1000); } public static DateTime DateTimeFromEpochMilliSeconds(this long milliseconds) { return FromEpochMilliseconds(milliseconds); } public static DateTime DateTimeFromEpochSeconds(this int seconds) { return FromEpochSeconds(seconds); } public static int ToEpochSeconds(this DateTime dt) { return (int)(ToEpochMilliseconds(dt)/1000); } public static long ToEpochMilliseconds(this DateTime dt) { return (long)(dt.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalMilliseconds; } } }
Labels: c#, epoch, Extension method, unix time
Tuesday, March 04, 2008
Synergy
I used to run x2vnc and win2vnc back in the MP3 days to let me control my Windows and linux boxen. Later I used the same setup with my old MacBook 15" and a Linux box. The other day, my friend n8 posted about his Synergy setup, which came perfectly timed. I just started a new gig at Bunkspeed and I'm using a dedicated desktop for dev instead of my MacBook Pro, but i don't want my Mac to be wasted. So i set up Synergy on both my home and work desktops and have the Mac on a stand running two Synergy clients (only one of which ever finds a server to connect to. This setup rules!Update: Don't know if this is something i'll find a way around, but apparently logging on to the VPN killed the connectivity between my desktop and mac :(
Update 2: Ok, as simple as going into the Advanced config and telling it what local IP to listen for connections on. All good again
Labels: synergy
