Bindings Not Working with Custom Content Control

Topics: Actions & Coroutines, Bootstrappers & IoC, Conventions
Feb 7, 2013 at 3:20 AM
Edited Feb 7, 2013 at 3:22 AM
I need help from you great experts!

I have a custom content control based on ContentControl that has Header, Content, Footer properties. It is very similar to the Microsoft HeaderedContentControl.

For some reason my bindings don't work in the Header and Footer. The ActiveItem binding in the Content works okay.

This control is the root of my shell and looks a little like this:
<Window...>
<c:UxtContent>
  <c:UxtContent.Header>
    <Grid>
      ... controls with bindings ... <-- bindings don't work
    </Grid>
  </c:UxtContent.Header>
  <c:UxtContent.Content>
    ... control with x:Name="ActiveItem" <-- works
  </c:UxtContent.Content>
  <c:UxtContent.Footer>
    <Grid>
      ... controls with bindings ... <-- bindings don't work
    </Grid>
  </c:UxtContent.Footer>
</c:UxtContent>
</Window>
In my Bootstrapper.cs, I created several different implementations of BindingScope.GetNamedElements in an effort to get CM to wire things up. I even went so far as to copy the implementation from the CM source and add in my UxtContent control where the HeaderedContentControl gets setup. In all cases, GetNamedElements is returning the named elements that sit inside my Header and Footer properties.

Here is a snippet from my GetNamedElements:
HeaderedContentControl control2 = control as HeaderedContentControl;
if ((control2 != null) && (control2.Header is DependencyObject))
{
  queue.Enqueue(control2.Header as DependencyObject);
}

UxtContent uxtc = control as UxtContent;
if ((uxtc != null) && (uxtc.Header is DependencyObject))
{
  queue.Enqueue(uxtc.Header as DependencyObject);
}
if ((uxtc != null) && (uxtc.Footer is DependencyObject))
{
  queue.Enqueue(uxtc.Footer as DependencyObject);
}
Still, it doesn't work.

Just to make sure I created an app using MVVM Light and one with Prism and everything works great with my custom content control.

I desperately need help!!

What am I missing?
May 10, 2013 at 8:22 AM
Hello!

Did you solve the problem? I have exactly the same problem here.

Thank you!!
May 10, 2013 at 3:40 PM
Nope. Unfortunately, we had to dump CM and move to MVVM Light. :(
May 12, 2013 at 11:32 AM
Hi RufusJWB,

Sorry to hear you have moved on however I feel it is important to mention that Caliburn.Micro supports standard binding just like MVVM Light, et al. Personally I prefer to make my bindings explicit, that way the intent is clearly shown in Xaml.
May 13, 2013 at 11:01 AM
In my case I solved it by using the (undocumented) Method 'AddCildResolver'.
            // ChildResolver for the AdornedControl
            BindingScope.AddChildResolver((p) =>
            {
                bool result = p == typeof(AdornedControl.AdornedControl);
                return result;
            }, (p) =>
            {
                var result = new List<DependencyObject>();

                var adornerControl = p as AdornedControl.AdornedControl;
                if (adornerControl != null)
                {
                    result.Add(adornerControl.AdornerContent);
                }
                return result;
            });
May 16, 2013 at 9:15 PM
Hello Rufus, can you explain a bit more how you implemented the AddChildResolver

Thank you good sir
May 17, 2013 at 8:10 AM
Hello!

There is not much more to explain. The above shown code is part of the OnStartup - method of my AppBootStrapper - class. The class AdornedControl is my Custom Content control. The first lambda statement
(p) =>
            {
                bool result = p == typeof(AdornedControl.AdornedControl);
                return result;
            }
is executed every time by Caliburn.Micro when it binds a VM to a V for every control of the V. If this statement returns 'true' the next lambda statement will be executed.
(p) =>
            {
                var result = new List<DependencyObject>();

                var adornerControl = p as AdornedControl.AdornedControl;
                if (adornerControl != null)
                {
                    result.Add(adornerControl.AdornerContent);
                }
                return result;
            }
This statement returns all child controls of the Content Control. You should modify this to reflect your implementation of your Content Control.

BR

Rufus