views:

202

answers:

2

I have a Window shell that is basically:

<Window>
    <ContentPresenter Content="{Binding}" />
</Window>

Injected into the ContentPresenter at run-time are UserControls. What I want to be able to do is write:

<UserControl Window.Title="The title for my window">
[...]
</UserControl>

So that the Window title is updated using the UserControl Window.Title property.

I have a feeling this can be achieved using attached properties. Can anyone start me off in the right direction?

Daniel

+2  A: 
public class MyUserControl : UserControl
{
   public static readonly DependencyProperty WindowTitleProperty = DependencyProperty.RegisterAttached("WindowTitleProperty",
                typeof(string), typeof(UserControl),
                new FrameworkPropertyMetadata(null, WindowTitlePropertyChanged));

        public static string GetWindowTitle(DependencyObject element)
        {
            return (string) element.GetValue(WindowTitleProperty);
        }

        public static void SetWindowTitle(DependencyObject element, string value)
        {
            element.SetValue(WindowTitleProperty, value);
        }

        private static void WindowTitlePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
                    Application.Current.MainWindow.Title = e.NewValue;
        }
}

<UserControl namespace:MyUserControl.WindowTitle="The title for my window">
[...]
</UserControl>
Yurec
This is almost correct, except you don't need to inherit from UserControl. Just change `public class MyUserControl : UserControl` to `public class MyUserControlBehaviour`. Bonus points for showing the correct XAML
Rob Fonseca-Ensor
I don't think you always want to change the title of the "Main Window"...
Heinzi
Heinzi is right, I want to change the Title of the Window element in which the user control resides. For example, when creating dialogs.
Daniel Skinner
then in property changed handler simply search parent window and set it's property.
Yurec
Thanks Yurec, this helped me arrive at the solution. See my answer for the final code.
Daniel Skinner
+2  A: 

I ended up using the following:

public static class WindowTitleBehavior
{
    public static readonly DependencyProperty WindowTitleProperty = DependencyProperty.RegisterAttached(
        "WindowTitleProperty", typeof(string), typeof(UserControl),
                 new FrameworkPropertyMetadata(null, WindowTitlePropertyChanged));

    public static string GetWindowTitle(DependencyObject element)
    {
        return (string)element.GetValue(WindowTitleProperty);
    }

    public static void SetWindowTitle(DependencyObject element, string value)
    {
        element.SetValue(WindowTitleProperty, value);
    }

    private static void WindowTitlePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UserControl control = d as UserControl;
        if (!control.IsLoaded)
        {
            control.Loaded += new RoutedEventHandler(setTitle);
        }
        setTitle(control);
    }

    private static void setTitle(object sender, RoutedEventArgs e)
    {
        UserControl control = sender as UserControl;
        setTitle(control);
        control.Loaded -= new RoutedEventHandler(setTitle);
    }

    private static void setTitle(UserControl c)
    {
        Window parent = UIHelper.FindAncestor<Window>(c);
        if (parent != null)
        {
            parent.Title = (string)WindowTitleBehavior.GetWindowTitle(c);
        }
    }
}

Which makes use of Philipp Sumi's code snippet to find the first ancestor Window: http://www.hardcodet.net/2008/02/find-wpf-parent

In my views I can now do:

<UserControl Behaviors:WindowTitleBehavior.WindowTitle="My Window Title">

And it sets the title of the containing Window.

Daniel Skinner
How do I modify the above code to allow me to do: <UserControl Behaviors:WindowTitleBehavior.WindowTitle="{Binding Title}"> I am currently getting a compile error.
Daniel Skinner