Register Now | Sign In
FeedGhost Logo

RSS feed Stu Smith: Making It Up As I Go Along

My life working for BinaryComponents, coding, design, and other stuff.

Naming Confusions in WPF


Posted on 29 Nov 2007 15:06

WPF provides a wide range of container controls that lay out their children in various ways (Grid, StackPanel, DockPanel, etc), but occasionally you need something slightly out-of-the-ordinary, and in those cases you have to write your own layout logic. For not-very-interesting reasons, I needed a container that would layout all its children on top of each other, using the full size of the parent container.

The usual method of achieving this is derive from the abstract class Panel, and implement your own MeasureOverride and ArrangeOverride methods. There's plenty of examples out there, but in most cases they assume that the layout is going to be at least partly dependent on the sizes of the child elements. Mine of course, isn't, so I wrote the following:

protected override Size MeasureOverride( Size availableSize )
{

// Error is here (missing code).


    return availableSize;
}

protected override Size ArrangeOverride( Size finalSize )
{
    var rect = new Rect( finalSize );

    foreach( UIElement child in InternalChildren )
    {
        child.Arrange( rect );
    }

    return finalSize;
}

...and it sort of worked, but only when expanding the control, not when shrinking. After half an hour of tearing my hair out, I finally found the answer in MSDN. (On a side note, it's a poor state of affairs when the official documentation is so bad that it's the last resort).

"UIElement.Measure()... Updates the DesiredSize of a UIElement."

Ah-ha! I should have measured my children! In my mind, while I can guess that arrange will change something, I just assumed that measure was free of side-effects, and so could be skipped. It's not, and I think that's slightly misleading naming. (Unless perhaps WPF elements are quantum...) The solution of course was to iterate the children in MeasureOverride, and measure each one, throwing away the results.

FeedGhost - Professional RSS Reading

Deleting Rows in LINQ-to-SQL


Posted on 06 Nov 2007 16:14

I spent a while this morning trying to figure out a rather strange error message while trying to delete data using LINQ, so I thought I'd pass on the answer.

Let's suppose we have two tables, Parent and Child, linked by a one-to-many foreign key relationship:

Parent - PK ParentId

Child - PK ChildId, FK OwnerParentId referenced Parent.ParentId

Now let's suppose you want to delete a child row from the parent:

parent.Children.Remove( child );

The error you get, assuming your foreign key column is non-nullable, is:

An attempt was made to remove a relationship between a Parent and a Child. However, one of the relationship's foreign keys (Child.OwnerParentId) cannot be set to null.

After a fair amount of searching, I've found this is because LINQ's default behaviour is simply to try to unlink the relationship by setting Child.OwnerParentId to null.

If you actually want to delete the child row instead, you'll need to amend your DBML file to specify a different DeleteOnNull rule. Right-click it and choose "Open with..." then "XML Editor". Find the appropriate association (and note each one appears twice, once for each direction - you need to edit the one in the child table) and set DeleteOnNull:

<Association Name="Parent_Child" Member="Parent" AccessModifier="Internal" ThisKey="OwnerParentId" Type="Parent" IsForeignKey="true" DeleteOnNull="true" />

Sorted!

FeedGhost - Professional RSS Reading

Why Is That Internal?


Posted on 05 Nov 2007 10:54

I'm a big fan of the .NET framework, so much so that for the past five years I haven't wanted to code in any other environment. Even so, sometimes I find myself getting frustrated with it - most recently when I was trying to get ASP.NET user controls (.ascx files) working from a different assembly (I mean come on - that's fairly basic - why won't ASP.NET let me do that?)

Since it's not a supported scenario, to get it to work I had to patch into the resource loading system, then fix up any field references and post-back events. Thanks to reflection I got it working in the end, but it's just so frustrating to be able to see the function I want to hook into in the call-stack or using Reflector, but not be able to because that function has internal accessibility.

I was pretty grumpy by then, so I decided to look into something that's been bothering me for a while now: why, whenever you want to do something slightly out-of-the-ordinary, do you find yourself blocked by the framework and its private, internal, non-virtual design?

I decided to focus on the 'internal' problem and knocked up a little application that scans the public types in an assembly, and counts the number of public, internal, and private, fields and methods. (I'm lumping public and protected in the same count since they're both part of the public contract of a class, and I'm only considering exported types since there can be good reasons to have internal classes with internal methods. For non-.NET coders, internal types are public to types in the same assembly, and private outside, a cousin to 'friend' in C++). Here's what we get for a selection of framework assemblies:

 

System Assemblies - % Internal

Yikes! Some of those assemblies are comprised 15% - 20% of internal methods. How come the System-Drawing team managed a design with just 1% internal, but the System-Xml-Linq team felt they needed nearly 20%?

'Internal' breaks a class's modularity and encapsulation. If you feel another class ought to be able to access a method, use public. If not, that's private. If you're using internal, you're too lazy to create a decent design.

When you have a lot of internal methods, you cease to have an assembly containing independent classes. You instead have a single, monolithic, assembly-sized class. You can't change anything without affecting every other class in your assembly.

I'm not saying that you have to get to 0% internal methods, just that that accessibility should be reserved for unusual cases. Some framework teams seem able to manage it. We've managed it, albeit in a much smaller project - see the screenshot below. Why can't the other framework teams?

 

FeedGhost Assemblies - % Internal

FeedGhost - Professional RSS Reading