Showing posts with label WTF. Show all posts
Showing posts with label WTF. Show all posts

Thursday, April 30, 2009

WPF DataGrid binding weirdness

Recently I had an object with a read-only property that I wanted to bind to a WPF DataGrid column. I expected an easy Binding="{Binding Path=MyProperty}" to accomplish it. However, when I made this change and tried to display the data at run-time, I got a bunch of exceptions:
A TwoWay or OneWayToSource binding cannot work on the read-only property 'MyProperty' of type 'MyObject'.
"Ok," I thought, "just change the binding's Mode."

So I assigned the value OneWay to Mode in the binding: Binding="{Binding Path=MyProperty, Mode="OneWay"}.

Same thing. No difference. Huh!?!?

After a bit of head scratching and digging through search results, I set the IsReadOnly property on the column to true.[1] That worked!

I removed the Mode assignment from the binding. It still worked!

Apparently, the DataGrid ignores the binding mode and sets it to what it thinks it should be, regardless of what it's told. Frustrating.
1. This post on GenericError.com pointed me in the right direction.

Wednesday, December 10, 2008

C# odditiy: Object initializer scope

I was reviewing some code today and ran across something that looked like this:
SomeProperty = SomeProperty

Odd, I thought that doesn't do anything, probably not what the writer intended. I sort of ignored it since I was doing some refactoring that removed that line anyway and went on. When I realized I didn't have any tests covering this bit of code, I saved my changes, reverted the unit, wrote a test and ran it, expecting a failure. Much to my surprise, it worked.

In context, the function looked sort of like this:
public class SomeClass
{
    public string SomeProperty { get; set; }

    public object Clone()
    {
        return new SomeClass { SomeProperty = SomeProperty };
    }
}

Looking at this, I expected both the SomeProperty properties to be in the scope of the object initializer and end up not doing anything, essentially assigning the property to itself. The test seemed to indicate otherwise. Thinking I had a problem with my test, I set some breakpoints and did some evaluation at run-time. I didn't see anything wrong with the tests and everything seemed to be working.

Still convinced something had to be wrong, I did some searching on the web trying to find somebody who talked about scoping rules in object initializers. Of course, I may not have hit on the correct search terms, but in any case I didn't find anything. So I wrote the following console application:
namespace TestObjectInitializerScopeConsole
{
    public class TestClass
    {
        public string TestText { get; set; }
    }

    class Program
    {
        public static string TestText { get; private set; }

        static void Main(string[] args)
        {
            TestText = "Some random text";
            Console.WriteLine("this.TestText = \"{0}\" (initially)", TestText);

            var test1 = new TestClass();
            Console.WriteLine("test1.TestText = \"{0}\" (without initializer)", test1.TestText);

            var test2 = new TestClass { TestText = TestText };
            Console.WriteLine("test2.TestText = \"{0}\" (with initializer)", test2.TestText);

            Console.WriteLine("Enter to finish...");
            Console.ReadLine();
        }
    }
}

According to this test, it seems to indicate the scope for items on the left hand of the assignment are the new object and those on the right hand are what you'd normally expect for the method. It seems pretty odd and anti-intuitive to have different scope like this.

Any comments? Am I missing something? Is this defined somewhere that I've missed? Does it seem weird to anyone else?

Wednesday, August 20, 2008

Never write software that fails silently!!

One of the tenets of software development is to fail early. The earlier something fails the less costly it is since you don't have as much invested as if it failed later. Visual Studio needs to learn this lesson.

I just spent the better part of an hour trying to figure out why a DeploymentItem attribute on a test didn't work. I had created some new files for the test, added them to the project and created an attribute that should have copied them over. The test didn't fail in the expected manner, because the code hadn't been updated to handle multiple files, but rather because there were no files at all. Setting a break point indicated that in fact the files were not being copied even though the were right there in the project.

After much frustration, I found through cygwin's grep the missing element: the files themselves needed to have their Copy to Output Directory property changed from Never to Every time. Why couldn't anything in the five steps leading up to the test execution have told me there might be a problem?

(And why did Explorer's Search fail to find the files that grep did?!?)