Design-time-only background color in WPF?

2019-02-01 03:06发布

问题:

In WPF XAML there is the convenient DesignHeight and DesignWidth, for instance in code as

<UserControl ... d:DesignHeight="500" d:DesignWidth="500" ... />

which is great because I can build the layout with a representative, but not locked-in, control size.

However, I'm often building dark UIs, where labels and so forth need to be white, but my controls still need a transparent background color. This creates a design-time inconvenience because white seems to be the default background color for transparent controls in the designer, leading to unreadable white-on-white labels.

Is there a way or strategy for setting the design-time background color, with similar convenience as DesignHeight/DesignWidth?

回答1:

There's an undocumented property d:DesignStyle of type Style that you can set on a user control. This style is only applied in the designer and is not used at runtime.

You use it like this:

<UserControl ... d:DesignStyle="{StaticResource MyDesignStyle}" />

Or like this:

<UserControl ...>
    <d:DesignerProperties.DesignStyle>
        <Style TargetType="UserControl">...</Style>
    </d:DesignerProperties.DesignStyle>
</UserControl>

Note however that any value set on the Style property (the one used at runtime) will also override the DesignStyle in the designer.



回答2:

I found that you can do one for yourself. Custom design-time attributes in Silverlight and WPF designer is a tutorial how to do it for both Silverlight and WPF.



回答3:

My answer was found here: Black Background for XAML Editor. There are a number of choices including checking System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) at runtime.



回答4:

The d:DesignerProperties.DesignStyle technique shown on this page works great for applying a WPF design-time-only style to a single control, but it doesn't appear to work for a Style in a ResourceDictionary that would apply to all of the appropriately-typed controls or elements under the scope of the dictionary. Below is simple solution I found for deploying a designer-only style into a ResourceDictionary.

Consider for example a Window containing a TreeView, where we want the TreeViewItem nodes to show as fully expanded—but only at design time. First, put the desired style in the XAML dictionary in the normal way.

<Window.Resources>
    <Style TargetType="TreeViewItem">
        <Setter Property="IsExpanded" Value="True" />
    </Style>
</Window.Resources>

Here, the Style is put in the ResourceDictionary of the Window but of course you could use any other subsuming dictionary instead. Next, in the C# code, remove the style from the Resource­Dict­ionary when design mode is not detected. Do this is in the OnInitialized override:

protected override void OnInitialized(EventArgs e)
{
    if (DesignerProperties.GetIsInDesignMode(this) == false)
        Resources.Remove(typeof(TreeViewItem));

    base.OnInitialized(e);
}

Design Mode:                                                        Runtime Mode:

   



回答5:

This is the complete solution for DesignBackground:

public class DesignTimeProperties : DependencyObject
    {
        private static readonly Type OwnerType = typeof(DesignTimeProperties);

        #region DesignBackground (attached property)

        public static Brush GetDesignBackground(DependencyObject obj)
        {
            return (Brush)obj.GetValue(DesignBackgroundProperty);
        }

        public static void SetDesignBackground(DependencyObject obj, Brush value)
        {
            obj.SetValue(DesignBackgroundProperty, value);
        }

        public static readonly DependencyProperty DesignBackgroundProperty =
            DependencyProperty.RegisterAttached(
                "DesignBackground",
                typeof (Brush),
                OwnerType,
                new FrameworkPropertyMetadata(Brushes.Transparent,
                    DesignBackgroundChangedCallback));

        public static void DesignBackgroundChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (IsInDesignMode)
            {
                var control = d as Control;
                var brush = e.NewValue as Brush;
                if (control != null && brush != null)
                {
                    control.Background = brush;
                }
            }
        }

        public static bool IsInDesignMode
        {
            get
            {
                return
                    ((bool)
                        DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof (DependencyObject)).DefaultValue);
            }
        }

        #endregion

    }

Usage:

<UserControl ... infra:DesignTimeProperties.DesignBackground="Black" />