Monday, December 22, 2008

California Supreme Court Redefines Good Samaritan

I was fairly shocked to learn the normally reasonable California Supreme Court  botch a case regarding Good Samaritan laws. An individual--who had been drinking and smoking marijuana--rendered aid at a motor vehicle accident pulling the driver from the allegedly smoking car. The driver suffered traumatic injuries to her liver, requiring surgery, and to her spine. Secondary to either the accident or the extrication, the driver suffered paraplegia and brought a negligence suit against the individual who had extricated her from the vehicle.

At trial, the original court agreed the defendant was covered under the Good Samaritan laws, as would be expected, however, on appeal this decision was overturned. The appeals court found that the statute covers only "emergency medical care" (ed: original emphasis) and not the actions taken by the defendant. Eventually the appeals reached the state supreme court, and the court found in favor of the plaintiff agreeing with the appeals court's finding that the care provided by the defendant--removing the plaintiff from her vehicle--was inconsistant with the language and intent of the applicable Good Samaritan statutes.

Huh?

Somehow, somewhere, the California Supreme Court has forgotten that removing your patient from harms way is the first step in patient care. Well okay, it comes after your safety, your partner's safety, and any bystander's safety (scene safe? BSI?). Still, if a patient is in a burning car, the first thing to do is remove the patient from the burning car. You cannot be expected to provide emergency medical care if the scene is not safe for you, your partner, or your patient. It stands to reason then, that the most fundamental form of Basic Life Support is removing your patient from danger.

What the California Supreme Court has done with their overly pedantic finding is to redefine a Good Samaritan and to change the rules of the game. The defendant in this case probably should be sued for negligence given all of the other facts in the case, however, they shouldn't be exempt from Good Samaritan laws merely because of a language technicality. People are already hesitant enough to provide bystander care with how lawsuit happy our society is, and now people in California have even less of a reason to provide care. Hopefully the legislature will iron this issue out in the new year.

Thursday, December 18, 2008

Wound Care and Non-Adherent Dressings

On our ambulance, the two least used forms of dressings are occlusive dressings and non-adherent dressings. It is easy to explain why we don't use occlusive dressings (ed: sucking chest wounds, while popular on ER, are NOT the mainstay of our site EMS), but it is a little bit harder to explain why we don't use non-adherent dressings often.

Typical wound care for an EMT-Basic consists of slapping a stack of 2x2, 3x3, or 4x4 gauze pads on the wound while applying direct pressure. If we have other things to do we'll ask the patient to hold the gauze, or tape it down. I can't ever recall ever using a non-adherent dressing or being asked for one; moreover, our wound care protocols do not give mention to them. Interestingly enough, before yesterday I probably would have been unable to give an indication for a non-adherent dressing without a little bit of thought.

Nothing could teach me the primary indication of a non-adherent dressing better than when I injured my knee yesterday. Just two small gouges, nothing big. I irrigated and debrided the wound, applied a 2x2" gauze, and secured the bandage with 1" cloth tape.

When I went to take a look at the wound that night, I was somewhat suprised to find the gauze had become part of the clot. I was even more supprised at the level of pain I was confronted with while removing the gauze-clot. The woven gauze had to be removed one strand at a time, even after applying warm water. It was at this point I had an epiphany.


My jump bag contains 4x4" non-adherent dressings that, surmising from their name, would not adhere to my wound like the gauze had. Sure enough, after cutting down the dressing to form a smaller 2x2" form, I applied the non-adherent dressing under a 2x2" gauze dressing, and taped the new and improved bandage down. Removal this morning was pain free, and further more I did not have to break any clots that had formed!

It only takes 5 seconds of googling to find that everyone from studies, to nurses, to patients emphatically support non-adherent dressings for wound care. Thanks to a personal lesson in pain, my own protocol for wound care will now include a non-adherent dressing for any wound (which will produce an exudate) upon which a dry sterile dressing will sit.

Sunday, November 9, 2008

Studying Paramedicine as a Software Engineer

Paramedic school has been grueling giving the concomitant (bordering on comorbid) factor of work. However, that will be my last complaint on that because as a general rule, when I want to do something, I go and do it. We've finished anatomy and physiology, pathophysiology, medicolegal concerns, various introductory topics, and most recently pharmocology.

We had to turn in cards on 72 drugs (of the 129 paramedics in NC could give), and I decided to make life easier for myself using a small program. LINQ-to-XML plus WPF (and some regular expressions to parse human readable dosages) allowed me to rapidly transcribe all of the useful information into an XML format. I then put together a quick XSLT file to make an OOXML file that I could print and paste to 3x5 index cards (ed: I left off side effects and had to add those by hand, wraaa!). Did I mention the program quizzes me on trade/generic names and pharmacological class? I'll try and release the quizzing features as a webpage at some point, however, my studies come first.


Right now we're having medical math beaten into us, which isn't particularly hard for those of us with strong mathematics backgrounds (ed: except when you suck at basic math). However, I noticed that many students had a hard time connecting the action of calculating a dosage with the mathematics to do the calculation. I put together a presentation to help bridge that gap, "Visualizing Medical Math" (PPTX). Hopefully this will help folks who are struggling with medical math.

(ed: for those of you without PowerPoint 2007 or access to a viewer, "Visualizing Medical Math" PDF).

Tuesday, October 21, 2008

Paramedic Student

Last night I became a paramedic student. From now until October 2009, I'll be in class three nights a week and the occasional Saturday. There are just over 30 students in our class, with a 60-40 split of EMT-Intermediates and EMT-Basics. Three students from my EMT-Basic class returned to study paramedicine, and I'm looking forward to studying with them again.

We have homework right out the gate, which isn't suprising giving the pace of the course. I'll be posting the thousand word paper on EMS history, the future of EMS, and where I fit into it all on this blog. We also have to do cards on 129 drugs available to paramedics in the great state of North Carolina. Each card will have the generic name, trade name, mechanism of action, dosages (all dosage possibilities, adult and pediatric), indications, contraindications, and side effects. Interestingly enough, most services only carry a fraction of these for emergent care, and often only carry specialized subsets for acute care. Regardless, I'm looking forward to the pharmacology review.

So, look forward to seeing more postings on my time as a paramedic student, and maybe postings on my clinicals during the new year. I refrain from posting about people I treat at work only due to the "small town" feel at work. When out in the world, I'll probably be able to write in generality.

Thursday, July 31, 2008

Fatal error LNK1171: unable to load c2.dll

We had an interesting problem arise where linking a Release mode static library written in C with a Fortran application using the Premier Partner edition of Visual Studio that ships with Intel Visual FORTRAN 10 would die at the linking stage. This happened late in the game as the debug mode builds of the C library did not exhibit this error. To make matters worse, if users had any other version of Visual Studio with just the Intel Visual FORTRAN Compiler Integration installed, no such problems arose.

Our first step was to install the Platform SDK: no joy. The second step was to manually copy the DLL's required (there are actually 3 DLL's you need) from a working install to the non-working install: success!

So, what could possibly be the problem here?

No amount of searching could turn up the issue, so a ticket was opened with Intel's Premier Support. Well, we should have done this from the beginning because it appears that the compiler writers themselves know a lot about the compiler toolchain; fancy that. The (relevant) response from Intel:
c2.dll is used by the Microsoft Visual C++ compiler to perform whole-program optimization. Might it be that this "release" C library was compiled with that option? If so, you will require Visual C++ to be installed in order to build using that library.

My advice is that if you know you will be linking a C library on a system with only Visual Studio Premier Partner Edition installed that you be sure that Whole Program Optimization is disabled, as otherwise Fortran programmers will not be able to use it.
Sure enough, disabling Whole Program Optimization on the Release mode builds of the C static library solved all of our issues.

Wednesday, July 16, 2008

Day 14: Denali National Park

We're 11 miles down Alaska Highway 3 (Parks Highway) at a school library. The weather is a bit bleh so we're unable to hike at the moment. We've now gone over 6500 miles on the road and are getting ready to make our return back to North Carolina. Here are some assorted photos from the park and our ascent of Mt. Healy (4500ft).




Tuesday, July 15, 2008

Day 13: Anchorage / Denali National Park

So now we've been on the road for nearly two weeks, and are at our halfway point. We've been to Tok, Delta Junctions, Fairbanks, Palmer, Valdez, Glennallen, Anchorage, and Seward. We've hiked to some glaciers, camped near some glaciers, and are about to spend a few nights in Denali National Park. I don't really have much more time in front of this computer, so I'll just leave you with a picture from the beginning (Dawson Creek, BC, Canada) and the end of the Alaska Highway (Delta Junction, AK).


Thursday, July 10, 2008

Day 8: Driving to Alaska

So we're at a public library in Fort St. John, BC, Canada, checking our email, chatting it up with friends. We've been on the road for 8 days and have driven 3715 miles (5975 km). We've seen ten states and two Canadian provences.

Travel Log (subtract 1581 original miles for total distance)
  • Greenburg, IN - Odo 2292 miles - $4.129/gal - 15.153gal
  • Mt. Prospect, IL - Odo 2566 miles
  • Janesville, WI - Odo 2652 miles - $4.169/gal - 14.936gal
  • Oxford, WI - Odo 2746 miles
  • King Island, MN - Odo 2985 miles - $3.919/gal - 13.225gal
  • Little Falls, MN - Odo 3064 miles
  • Fargo, ND - Odo 3237 miles - $3.899/gal - 10.289gal (10% ethanol)
  • Jamestown, ND - Odo 3328 miles
  • Dickenson, ND - Odo 3501 miles - $4.149/gal - 12.717gal
  • Medroa, ND - Odo 3567 miles
  • Miles City, MT - Odo 3747 miles - $4.099/gal - 12.349gal
  • Livingston, MT - Odo 4002 miles
  • Big Timber, MT - Odo 4033 miles - $4.099/gal - 18.438gal (85.5 octane, 5gal spare)
  • Ackley Lake State Park, MT - Odo 4143 miles
  • Great Falls, MT - Odo 42131 miles - $4.099/gal - 8.158gal
  • Calgary, AB, Canada - Odo 4570 miles (7355 km) - CAD1.379/L - 51.793L
  • Lake Louise, AB, Canada - Odo 4673 miles (7520 km)
  • Drayton Valley, AB, Canada - Odo 4897 miles (7881 km) - CAD1.349/L - 49.314L
  • Dawson Creek, BC, Canada - Odo 5239 miles (8431 km) - CAD1.419/L - 56.675L (10% ethanol)
  • Kiskatinaw, BC, Canada - Odo 5259 miles (8464 km)
  • Fort St. John, BC, Canada - Odo 5296 miles (8523 km)

Next time I'll post it will probably be in Fairbanks, AK on the 13th.

Thursday, July 3, 2008

Destination Alaska


So yesterday my youngest brother and I started our drive to Alaska. 10,200 miles in total, we've gone just over 500 on our first leg. We're in West Virginia with our other brother and his fiancée, both Marshall students. Tomorrow we are headed to Chicago for the fourth and a beach party. My new car is getting about 25mpg while it is still getting broken in. I'll keep a log going of the miles driven, gas consumed, and prices per gallon whenever I get the chance.

Itinerary
  • 03 July - Huntington, WV
  • 04 July - Chicago, IL
  • 05 July - Oxford, WI and Little Falls, MN
  • 06 July - Medora, ND
  • 07 July - Great Falls, MT
  • 08 July - Banff, AB Canada
  • When I figure out the rest I'll let you know!
Travel Log
  • Wilmington, NC - Odo 1581 miles - Gas $3.979 - 8.958gal
  • Cary, NC - Odo 1715 miles
  • Wytheville, VA - Odo 1907 miles - $3.899 - 13.658gal
  • Huntington, WV - Odo 2084 miles

Sunday, June 22, 2008

Wilderness EMT

This last week was quite the week. I drove out to Sylva, NC to take a Wilderness EMT class--also known as the Wilderness Upgrade for Medical Professionals (WUMP)--at Landmark Learning. On the way I had to make a two hour diversion due to a serious wreck on I-40 at exit 355 which knocked off a piece of the overpass, backing up traffic for almost 10 miles! However, this did afford me the opportunity to take my new car through the mud to make a U-turn on the highway.

Anyways, the Wilderness EMT certification is administered through the Wilderness Medicine Institute of the National Outdoor Leadership School (WMI of NOLS). Landmark Learning is one of the partners of WMI that teaches the course. It was 6 days long, including two night classes. We covered every topic you would cover in your urban EMT-B class, just assuming you were out in the back country.

Without a doubt, the Wilderness EMT course was one of the most fun classes I have ever taken. Furthermore, I learned more in the last week than I ever did in 5 months of EMT school and my (now) 6 months of experience. Our two teachers, Justin and Jon, were perfect foils for one another. They were knowledgeable, hilarious, serious, and extremely competent teachers all at the same time. They taught the course as much outside and hands-on as we sat inside listening to lecture. The lecture was so interactive, nobody sat pounding nails or twiddling their thumbs. Justin and Jon fully expected that everybody in the room would participate, as we were all at least EMT-B's (and a PA) and should know the majority of the information. They just took what we knew and molded it into a back country way of thinking. This dynamic style of learning made for a truely amazing week and has made me a better (urban) EMT!

While Justin and Jon were the stars of the show there at Landmark Learning, enough can't be said for the interesting cast of people making up the student body. We had ex-special forces, current military, paramedics, a PA, fire fighters, current EMT's, and brand spankin' new EMT's. The brand spankin' new EMT's were fresh out of Landmark Learning's EMT Intensive program, where they spent 19 days at the campus getting fashioned into National Registry EMT-Basics. It is a testament to the amazing educational experience at Landmark to see a large number of them stay through the WEMT program and hold their own with more experienced medical professionals! Thanks also go to the other students for making six solid days of learning seem like the blink of an eye.

I feel well prepared for my drive to and from Alaska. I have a new car that will go the distance. My brother has his Wilderness First Aid certification (taught by J-Lo of Landmark), and I'm now a WEMT. I think all I need at this point is some experience hiking and camping...crap.

Monday, May 12, 2008

WPF Application Quality Guide v0.2

Microsoft has released v0.2 of their WPF Application Quality Guide, which contains some great new items in the application testing section. They go over some interesting ways you can test a GUI application, including media sections of an application. I must say I hadn't thought about taking a screenshot of the desired result and then using an image differencing tool on the user's screenshot as a method of acceptance testing. That section definitely got me thinking on how to streamline our own GUI testing practices (read: nonexistent). I have cleaned up versions of their sample code, and if you'd like it just shoot me an email.

Monday, April 21, 2008

RE: NTDebugging Puzzler 0x00000003 (Matrix Edition) Some assembly required

So the Microsoft Advanced Windows Debugging and Troubleshooting blog put out a puzzler based on reverse engineering assembler into something meaningful, say C/C++. I took a look at the assembly listing and decided it would be a fun break from work to decompile that into something. About 30 minutes later I wound up with some source that compiles down to nearly the same listing as theirs.

Phew, I've still got it! It took me some time monkeying around with the order of the local variables to get the same space added for the locals as in their example. Other than that it was pretty straight forward.
puzzler3.cpp
#include <stdlib.h>
#include <string.h>

/** Sort an input string's characters in descending order
*
*/
// puzzler3!myfun [c:\source\puzzler\puzzler3\puzzler3\puzzler3.cpp @ 20]:
void myfun(char* arg0)
// 20 00cc1480 55 push ebp
// 20 00cc1481 8bec mov ebp,esp
// 20 00cc1483 81ecf0000000 sub esp,0F0h
// 20 00cc1489 53 push ebx
// 20 00cc148a 56 push esi
// 20 00cc148b 57 push edi
{
//union { // [ebp-0F0h]
// struct {
size_t arg0_len; // [ebp-08h]
// unsigned int pad0; // [ebp-0Ch]
// unsigned int pad1; // [ebp-10h]
size_t ii; // [ebp-14h]
// unsigned int pad2; // [ebp-18h]
// unsigned int pad3; // [ebp-1Ch]
size_t len_temp; // [ebp-20h]
// unsigned int pad4; // [ebp-24h]
// unsigned int pad5; // [ebp-28h]
char x; // [ebp-29h]
// };
// unsigned char local_variables[240];
//}; // local variables

// //set local variables to unusual values for buffer checking
//memset(local_variables,
// 0xCCCCCCCCU,
// sizeof(local0)/sizeof(unsigned int)
//); // 20 00cc148c 8dbd10ffffff lea edi,[ebp-0F0h]
// 20 00cc1492 b93c000000 mov ecx,3Ch
// 20 00cc1497 b8cccccccc mov eax,0CCCCCCCCh
// 20 00cc149c f3ab rep stos dword ptr es:[edi]

len_temp = strlen(arg0); // 26 00cc149e 8b4508 mov eax,dword ptr [ebp+8]
// 26 00cc14a1 50 push eax
// 26 00cc14a2 e803fcffff call puzzler3!ILT+165(_strlen) (00cc10aa)
// 26 00cc14a7 83c404 add esp,4
// 26 00cc14aa 8945e0 mov dword ptr [ebp-20h],eax
// 28 00cc14ad 8b45e0 mov eax,dword ptr [ebp-20h]
// 28 00cc14b0 8945f8 mov dword ptr [ebp-8],eax

for(arg0_len = len_temp; arg0_len > 0; arg0_len--)
// 28 00cc14b5 8b45f8 mov eax,dword ptr [ebp-8]
// 28 00cc14b8 83e801 sub eax,1
// 28 00cc14bb 8945f8 mov dword ptr [ebp-8],eax
// 28 00cc14b3 eb09 jmp puzzler3!myfun+0x3e (00cc14be)
// 28 00cc14be 837df800 cmp dword ptr [ebp-8],0
// 28 00cc14c2 7e60 jle puzzler3!myfun+0xa4 (00cc1524)
{
// 30 00cc14c4 c745ec00000000 mov dword ptr [ebp-14h],0
// 30 00cc14cb eb09 jmp puzzler3!myfun+0x56 (00cc14d6)
for(ii = 0; ii < (arg0_len - 1); ii++)
// 30 00cc14cd 8b45ec mov eax,dword ptr [ebp-14h]
// 30 00cc14d0 83c001 add eax,1
// 30 00cc14d3 8945ec mov dword ptr [ebp-14h],eax

// 30 00cc14d6 8b45f8 mov eax,dword ptr [ebp-8]
// 30 00cc14d9 83e801 sub eax,1
// 30 00cc14dc 3945ec cmp dword ptr [ebp-14h],eax
// 30 00cc14df 7d41 jge puzzler3!myfun+0xa2 (00cc1522)
{
//char temp0 = arg0[ii]; // 32 00cc14e1 8b4508 mov eax,dword ptr [ebp+8]
// 32 00cc14e4 0345ec add eax,dword ptr [ebp-14h]
// 32 00cc14e7 0fbe08 movsx ecx,byte ptr [eax]
//char temp1 = arg0[ii + 1]; // 32 00cc14ea 8b5508 mov edx,dword ptr [ebp+8]
// 32 00cc14ed 0355ec add edx,dword ptr [ebp-14h]
// 32 00cc14f0 0fbe4201 movsx eax,byte ptr [edx+1]


// 32 00cc14f4 3bc8 cmp ecx,eax
// 32 00cc14f6 7e28 jle puzzler3!myfun+0xa0 (00cc1520)
if(arg0[ii + 1] > arg0[ii])
{
x = arg0[ii]; // 34 00cc14f8 8b4508 mov eax,dword ptr [ebp+8]
// 34 00cc14fb 0345ec add eax,dword ptr [ebp-14h]
// 34 00cc14fe 8a08 mov cl,byte ptr [eax]
// 34 00cc1500 884dd7 mov byte ptr [ebp-29h],cl

arg0[ii] = arg0[ii+1]; // 35 00cc1503 8b4508 mov eax,dword ptr [ebp+8]
// 35 00cc1506 0345ec add eax,dword ptr [ebp-14h]
// 35 00cc1509 8b4d08 mov ecx,dword ptr [ebp+8]
// 35 00cc150c 034dec add ecx,dword ptr [ebp-14h]
// 35 00cc150f 8a5101 mov dl,byte ptr [ecx+1]
// 35 00cc1512 8810 mov byte ptr [eax],dl
arg0[ii+1] = x; // 36 00cc1514 8b4508 mov eax,dword ptr [ebp+8]
// 36 00cc1517 0345ec add eax,dword ptr [ebp-14h]
// 36 00cc151a 8a4dd7 mov cl,byte ptr [ebp-29h]
// 36 00cc151d 884801 mov byte ptr [eax+1],cl
}
} // 38 00cc1520 ebab jmp puzzler3!myfun+0x4d (00cc14cd)
} // 40 00cc1522 eb91 jmp puzzler3!myfun+0x35 (00cc14b5)

// return and ensure our stack is still correct
return; // 41 00cc1524 5f pop edi
// 41 00cc1525 5e pop esi
// 41 00cc1526 5b pop ebx
// 41 00cc1527 81c4f0000000 add esp,0F0h
// 41 00cc152d 3bec cmp ebp,esp
// 41 00cc152f e820fcffff call puzzler3!ILT+335(__RTC_CheckEsp) (00cc1154)
// 41 00cc1534 8be5 mov esp,ebp
// 41 00cc1536 5d pop ebp
// 41 00cc1537 c3 ret
}

puzzler3_driver.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void myfun(char *arg0);

int main(int argc, char* argv[])
{
char *test = NULL;

test = (char *)calloc(strlen(argv[0]) + 1, sizeof(char));
strcpy(test, argv[0]);

printf("%s\n", test);
myfun(test);
printf("%s\n", test);

return 0;
}

You'll need an MSVC compiler, probably circa VS2k5 or later, with /Od /GS /RTC1 /FA /Fa"bin\\" to get a listing that'll look like their listing.

Friday, April 18, 2008

Lessons Learned Transporting Patients

I've learned quite a few things lately transporting patients. Correction, I've relearned quite a few things transporting patients. It isn't like I did not already know what to do, or what I was expected to do, I'm just new. Green. Wet behind the ears. A pain in the ass for admit nurses.

No matter how much of a Real American Badass(tm) you are, no matter how Rain Man-esque you are with numbers, always have your run sheet in front of you when you call in to the hospital. Nothing makes you look like more of an idiot than rattling off a long set of vitals to the admit nurse and then fumbling a curveball question thrown at you like, "his age?" Your lack of an automatic response to this question lets them know you're now covering the phone to ask the patient.

Also, if you have any doubt what any of the medications your patient is on are for, take the 30 seconds to look them up in your field guide. The physician may only be quizzing you when they ask if the patient is on a specific class of drugs, but wouldn't you rather have the correct answer for them than say you are unsure what one of the medications is for?

The biggest problem I've found is not that I'm lacking any of the training necessary to fulfill my position as an EMT, just that it isn't automatic for me yet. You can imagine the level of frustration with myself considering my talents in other fields.

Wednesday, April 9, 2008

Shell Context Menu Slow to Open

Recently I've had a problem on my home machine where when right clicking on various shell items (not every shell item) could take 1-2 minutes to bring up the context menu. Explorer would go 'Not Responding', yet take up 0% CPU. Obviously something was blocking in Explorer, and I figured it to be one of my context menu handlers. Context menu handlers are buried within the registry in an expansive set of keys for literally every type of file system object on your computer. Locating every context menu handler is a tall order, but with a little help from Google, I found that NirSoft has an amazing tool called ShellExView which allows you to view all hooks into the Shell, and disable them en masse.

The first step I took was disabling every Context Menu and Property Sheet handler. Then I restarted my machine, and prepared to slowly re-enable them until I found the offending handler. ShellExView has a cool sort method to sort by company, which I tried first, but found no relief. Eventually I discovered that no matter how many things I disabled, my context menu was still slow as dirt.

Then I cut off my network card. Windows loves to take its time trying to find UNC paths--as you're well aware if you've ever mistyped a network share into Start/Run--so I chanced to gather that some shell verb pointed to something on a network path that was no longer there. Viola! Without a network connection my shell context menu's came up at regular speed.

How on earth do I easily find the culprit? There is some shell verb with a UNC path being referenced, and the Registry is a mighty large place. Once again NirSoft1 came to the rescue with their Registry search tool RegScanner. Set it to search for "\\" and stand back for the deluge of UNC paths found in your registry. Open and delete2 any branches that look like [Something\shell\*\command] and have a UNC path in the key. Mine was a program I used once on a Samba share that somehow made its way into my Open list.

Once I removed the offending key, it was back to business as usual.

1. nota bene: I did not intend for this to be a NirSoft shill post, but they really do have the two most useful tools for diagnosing Shell hook problems.

2. nota bene: if you aren't willing to live with toasting your Windows install, you may be inclined to export any keys you delete. I, however, am not so inclined.

Monday, April 7, 2008

Zooming Objects Inside a WPF ItemsControl

Previously I've shown how to zoom objects in WPF using either an attached property or directly binding a LayoutTransform. If you'd like to zoom objects inside of an ItemsControl, you can use a slight variation on the direct binding strategy.

First you should style the ItemsPanel template for your ItemsControl, in this case a ListBox.
<ItemsPanelTemplate x:Key="ZoomedItemsPanel">
<StackPanel IsItemsHost="True">
<StackPanel.LayoutTransform>
<ScaleTransform
ScaleX="{Binding Path=Value, ElementName=ZoomSlider}"
ScaleY="{Binding Path=Value, ElementName=ZoomSlider}" />
</StackPanel.LayoutTransform>
</StackPanel>
</ItemsPanelTemplate>

Then your ListBox can reference the ZoomedItemsPanel and enjoy zooming on just its contents!
<Label Content="Zoom: "
Target="{Binding ElementName=ZoomSlider}" />
<Slider x:Name="ZoomSlider"
Minimum="0.25"
Value="1"
Maximum="5"
SmallChange="0.5"
LargeChange="1.0" />
<ListBox ItemsPanel="{DynamicResource ZoomedItemsPanel}" />

Wasn't that easy?

Friday, March 7, 2008

WPF TileBrush Nonsense

For the absolute life of me I cannot get a custom TileBrush to tile outside of VS2k8 or Blend 2.5. The basics are that I'm constructing a ruler, which started programmatically after finding the current DPI. When that didn't work, I attempted to do the same thing in straight XAML, which wouldn't be relative to the DPI (thus would only be a nice ruler at 96dpi). Even this would not work. At this point my frustration knows no bounds.

The above is a screengrab from inside VS2k8. The screengrab from Blend 2.5 also shows the ruler tiling. Below is a screengrab during runtime, notice the distinctive lack of tiling, and now it is somehow stretching to Fill.

The tiled brush is a DrawingBrush consisting of a GeometryDrawing with a GeometryGroup of LineGeometry's. The annotated XAML is given below:
<DrawingBrush x:Key="RulerBrush"
Stretch="None"
TileMode="Tile"
Viewport="0,0,96,16"
ViewportUnits="Absolute"
Viewbox="0 0 1 1"
ViewboxUnits="RelativeToBoundingBox">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<GeometryGroup>
<LineGeometry EndPoint="0,16"
StartPoint="0,0" />
<!-- ... -->
<LineGeometry EndPoint="48,16"
StartPoint="48,4" />
<!-- ... -->
<LineGeometry EndPoint="96,16"
StartPoint="96,0" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Brush="#FF000000"
Thickness="1" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>

And the requisite XAML for the display area:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Test.Window1"
x:Name="Window"
Title="Window"
Width="640"
Height="480">
<DockPanel x:Name="LayoutRoot" LastChildFill="True">
<ToolBarTray x:Name="ToolBarTray"
DockPanel.Dock="Top">
<ToolBar x:Name="MenuToolBar"
ToolBar.Band="0"
Width="{Binding Path=ActualWidth, ElementName=ToolBarTray}" />
</ToolBarTray>
<Rectangle x:Name="RulerY"
DockPanel.Dock="Left"
Height="15" Margin="0,15,0,0"
Fill="{DynamicResource RulerBrush}">
<Rectangle.LayoutTransform>
<RotateTransform Angle="-90.0" />
</Rectangle.LayoutTransform>
</Rectangle>
<Rectangle x:Name="RulerX"
DockPanel.Dock="Top"
Height="15" Margin="0,0,0,0"
Fill="{DynamicResource RulerBrush}"/>
<ScrollViewer Style="{DynamicResource SimpleScrollViewer}"/>
</DockPanel>
</Window>

This is fairly obnoxious!

Friday, February 8, 2008

Writing Quality WPF Applications

I've got together a few resources which are helpful when attempting to write a quality WPF application. While some of them are for C# 2.0 or .Net 2.0, I feel they are just as valid in C# 3.0 and .Net 3.5.

Without further ado, the (currently short) list:
Hopefully in the future there will be more guides for effective WPF development!

Thursday, January 31, 2008

NREMT-B and NCEMT-B

I passed both the National Registry EMT-Basic and North Carolina EMT-Basic certifications in December and January respectively. Soon I will be volunteering with a local EMS unit, probably at night. In March I will be taking Wilderness EMT training and finally in August I start Paramedic school. Lots of fun to be had in the near future!

Thursday, January 24, 2008

Where the &%$@ is HashSet?

If you've created a .Net 3.5 project in Expression Blend 2 (December Preview) and then opened it up in VS2k8, you may have noticed that using System.Collections.Generic does not give you HashSet.
The type or namespace name 'HashSet' could not be found.
You may be gnashing your teeth over this, but the simple solution is to add System.Core.dll as a reference to your project because it appears Blend 2 leaves this out.

Update: Zoom multiple controls from the same slider in XAML

I've had a serious learning curve with XAML, and frequently find new and better ways of doing things. A good example of this is zooming multiple controls from the same slider. My previous solution used a DependencyProperty and an IValueConverter and was probably slow as dirt if you wired up more than a few controls to get zoomed. A much more succinct, maintainable, and readable solution would be:
<Page class="ZoomTest.Page1" name="page" xmlns="...">
xmlns:local="clr-namespace:ZoomTest"
local:AttachedProperties.Zoom="0.8">
<Grid>
<Grid.LayoutTransform>
<ScaleTransform ScaleX="{Binding Path=Zoom,
ElementName=page}"
ScaleY="{Binding Path=Zoom,
ElementName=page}" />
</Grid.LayoutTransform>
</Grid>
</Page>
And yes, while I do have two bindings, it actually is very fast. One of the big things I've learned is you can really (ab)use the binding system and strangely enough have a faster UI than one you control! In a GUI application I'm designing in WPF, there are over 5000 data bindings on just one page, and yet it is nearly twice as fast as the version where I practically precompute the whole UI! My only guess as to why this is the case is that UIElement's are much more expensive than data bindings.

Another way to tackle the above problem, if say you're on the same UI without Page's, is actually much simpler:
<Window ...>
<DockPanel x:Name="LayoutRoot"
LastChildFill="True">
<StackPanel DockPanel.Dock="Top">
<Slider x:Name="ZoomSlider"
Minimum="1" Value="5" Maximum="10" />
</StackPanel>
<ScrollViewer>
<Grid x:Name="content">
<Grid.LayoutTransform>
<ScaleTransform ScaleX="{Binding Path=Value,
ElementName=ZoomSlider}"
ScaleY="{Binding Path=Value,
ElementName=ZoomSlider}" />
</Grid.LayoutTransform>
</Grid>
</ScrollViewer>
</DockPanel>
</Window>
Using strategies like this you can use less C# and more XAML. I've been able to take over 7000 lines of presentation code written for Java 1.4 (the C# 2.0 code would be roughly the same size) and turn it into roughly 550 lines of XAML and 100 lines of C# 3.0. Expect more little fun things you can do with WPF soon (like making a ListBox do whatever you please).