One thing has been really annoying me for a long time – when I was setting IsEnabled property on some WPF container to false all its contained controls automatically became disabled as well. Ok, that really wasn’t a source of my annoyance – it was rather expected. Really frustrating thing is that you are unable to scroll a DataGrid, to copy and paste a text from TextBox etc. One can say – but there is a ReadOnly property – and he’s going to be right, but unfortunately it’s available on only few of these controls. TextBox for instance has an IsReadOnly property and DataGrid control that I’m currently using has a ReadOnly property.

After a while of googling and finding nothing I decided to do it my way. At first I thought that it will be a great idea to have an attached property on one of container controls. That control could recursively look through all its children’s and decide whether it should be set to ReadOnly or Enabled. Few whiles later I had my code ready but something wasn’t right. When I was trying to iterate through my controls collection it turned out that my container is empty ? But it wasn’t. Ok, in fact it was at that moment, apparently the visual/logical tree is empty until the Window undergoes layout at least once. Now that was a pity. I had an option to do it by utilizing OnContentRendered(EventArgs e) event method but it would rather make my code ugly, dependent and evil.

Finally I decided do create some extension methods and set this property from code-behind. It’s still something that I’m not proud of, but well, it works. If someone has a better idea please don’t hesitate to write a comment or contact me.

Some code:

public static class ControlsExtensions
{
    public static void IsReadOnly(this GroupBox gb, bool isReadOnly)
    {
        RecurseTree(gb, isReadOnly);
    }

    // more extension methods for other containers...

    private static void RecurseTree(FrameworkElement control, 
                                    bool isReadOnly)
    {
        foreach (var c in LogicalTreeHelper.GetChildren(control))
        {                
            var frameworkElement = c as FrameworkElement;
            if (frameworkElement == null) continue;

            var tb = c as TextBox;
            if (tb != null)
            {
                tb.IsReadOnly = isReadOnly;
                continue;
            }

            var dg = c as SomeDataGrid;
            if (dg != null)
            {
                dg.ReadOnly = isReadOnly;
                continue;
            }

            if (c is GroupBox || c is DockPanel || c is Grid 
                || c is StackPanel || c is TabControl)
            {
                RecurseTree(frameworkElement, isReadOnly);
            }
            else
            {
                frameworkElement.IsEnabled = !isReadOnly;
            }
        }
    }
}

You might notice that I don’t repeat recursion for not container types – that is intentional in terms of my project, and it saves a few processor cycles.

I do think that somewhere out there is a more elegant solution, if you know one please let me know.

Technorati Tagi:
About
Dawid Kowalski Dawid Kowalski is software developer, traveler and strong advocate of "let's go do it".


Recent Posts
Recent Comments
Twitter
Syndication
Hosted by