在WPF设计器中设计标记扩展参数的时间

时间:2013-04-09 12:54:35

标签: c# wpf markup-extensions visual-studio-designer

我为WPF编写了一个标记扩展,允许我这样做

<!-- Generic Styles -->
<Style x:Key="bold" TargetType="Label">
    <Setter Property="FontWeight" Value="ExtraBold" />
</Style>

<Style x:Key="italic" TargetType="Label">
    <Setter Property="FontStyle" Value="Italic" />
</Style>

<Style x:Key="gridHeader" TargetType="Label" 
    BasedOn="{WPF:CombiStyle bold italic }" >

这是一个非常有用的扩展,它在运行时运行良好。然而 在设计时我看不到应用的样式或if 我输错了粗体和斜体它们可能找不到 as StaticResources。

我能做些什么来搞定这个?

扩展程序的源代码是

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Markup;

namespace MarkupExtensions
{
    [MarkupExtensionReturnType(typeof(Style))]
    public class CombiStyleExtension : MarkupExtension
    {

        private string[] MergeStyleProviders { get; set; }

        public CombiStyleExtension(string s0)
        { 
            MergeStyleProviders = s0.Split(new[]{' '});
        }

        public override object ProvideValue(IServiceProvider
                                            serviceProvider)
        {
            return MergeStyleProviders
                .Select(x => StringToStyle(serviceProvider, x))
                .Aggregate(new Style(), RecursivelyMergeStyles);
        }

        private static Style StringToStyle(IServiceProvider serviceProvider, string x)
        {
            var style = new StaticResourceExtension() { ResourceKey = x }.ProvideValue(serviceProvider) as Style;
            if (style==null)
            {
                throw new ArgumentException("Argument could not be converted to a style");
            }
            return style;
        }

        private static Style RecursivelyMergeStyles(Style accumulator,
                                           Style next)
        {
            if (next.BasedOn != null)
            {
                RecursivelyMergeStyles(accumulator, next.BasedOn);
            }

            MergeStyle(accumulator, next);

            return accumulator;
        }

        private static void MergeStyle(Style targetStyle, Style sourceStyle)
        {
            targetStyle.TargetType = sourceStyle.TargetType;
            // Merge the Setters...
            foreach (var setter in sourceStyle.Setters)
                targetStyle.Setters.Add(setter);

            // Merge the Triggers...
            foreach (var trigger in sourceStyle.Triggers)
                targetStyle.Triggers.Add(trigger);
        }

    }
}

2 个答案:

答案 0 :(得分:3)

更新: VS2012 添加了屏幕截图(工作正常)和 VS2012的Blend (部分工作:基于非基础风格的基础样式不是因某种原因正确选择了。)

还在 VS2013预览混合VS2013预览中进行了检查 - 它的工作部分与 Blend for VS2012 完全相同。希望他们在发布时解决这个问题。

Works in VS2012 as good as in VS2010

In Blend for VS2012 it works partionally

问题在于,当您尝试在XAML中描述的对象具有用于实例化该对象的设计时实例的公共默认构造函数时,Visual Studio设计者非常喜欢。

我已经对您的 CombiStyleExtension.cs 类进行了更新,以便将此考虑在内,而Visual Studio 2010设计师就是这样。然而,Blend 4设计师仍然没有,抱歉。

看看:

using System;
using System.Linq;
using System.Windows;
using System.Windows.Markup;

namespace WpfApplication7
{
    [MarkupExtensionReturnType(typeof(Style))]
    public class CombiStyleExtension : MarkupExtension
    {
        /// <summary>
        /// Set space-separated style names i.e. "size16 grey verdana".
        /// </summary>
        public string Names { private get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return Names.Split(new[] { ' ' })
                        .Select(x => Application.Current.TryFindResource(x)
                            as Style)
                        .Aggregate(new Style(), RecursivelyMergeStyles);
        }

        private static Style RecursivelyMergeStyles(Style accumulator,
                                                    Style next)
        {
            if(accumulator == null || next == null)
                return accumulator;

            if(next.BasedOn != null)
                RecursivelyMergeStyles(accumulator, next.BasedOn);

            MergeStyle(accumulator, next);

            return accumulator;
        }

        private static void MergeStyle(Style targetStyle, Style sourceStyle)
        {
            if(targetStyle == null || sourceStyle == null)
            {
                return;
            }

            targetStyle.TargetType = sourceStyle.TargetType;

            // Merge the Setters...
            foreach(var setter in sourceStyle.Setters)
                targetStyle.Setters.Add(setter);

            // Merge the Triggers...
            foreach(var trigger in sourceStyle.Triggers)
                targetStyle.Triggers.Add(trigger);
        }
    }
}

此标记扩展的使用也发生了一些变化。怎么样:

BasedOn="{WPF:CombiStyle bold italic }"

以及它现在如何:

BasedOn="{WPF:CombiStyle Names='bold italic'}"

只是为了节省一些时间,这里有一些复制粘贴运行和观看的xaml:

<强> MainWindow.xaml

<Window x:Class="WpfApplication7.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WPF="clr-namespace:WpfApplication7"
        Title="MainWindow" Height="350" Width="569">
    <Window.Resources>
        <!-- Did not managed to make the type-level style work -->
        <!-- from app.xaml, so put it here. Just in case. -->
        <Style TargetType="{x:Type Label}"
                  BasedOn="{WPF:CombiStyle Names='size16 grey verdana'}" />
    </Window.Resources>
    <StackPanel>
        <Label Content="Type-level: size16 + grey + verdana" />
        <Label Content="'h1': size24 + royalBlue" Style="{DynamicResource h1}" />
        <Label Content="'warning': size24 + yellow + bold + shadow"
                   Style="{DynamicResource warning}" />
        <Label Content="Inline: size12 + italic"
                   Style="{WPF:CombiStyle Names='size12 italic'}" />
        <Label Content="Inline: size16 + bold + italic + red"
                   Style="{WPF:CombiStyle Names='size16 bold italic red'}" />
        <Label Content="Inline: size24 + green"
                   Style="{WPF:CombiStyle Names='size24 green'}" />
    </StackPanel>
</Window>

<强>的App.xaml

<Application x:Class="WpfApplication7.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:WPF="clr-namespace:WpfApplication7"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <!-- Sizes -->
        <Style x:Key="size12" TargetType="Label">
            <Setter Property="FontSize" Value="12" />
        </Style>
        <Style x:Key="size16" TargetType="Label">
            <Setter Property="FontSize" Value="16" />
        </Style>
        <Style x:Key="size24" TargetType="Label">
            <Setter Property="FontSize" Value="24" />
        </Style>
        <!-- Bold/Italic -->    
        <Style x:Key="bold" TargetType="Label">
            <Setter Property="FontWeight" Value="ExtraBold" />
        </Style>
        <Style x:Key="italic" TargetType="Label">
            <Setter Property="FontStyle" Value="Italic" />
        </Style>
        <!-- Colors --> 
        <Style x:Key="grey" TargetType="Label">
            <Setter Property="Foreground" Value="#333333" />
        </Style>
        <Style x:Key="royalBlue" TargetType="Label">
            <Setter Property="Foreground" Value="RoyalBlue" />
        </Style>
        <Style x:Key="green" TargetType="Label">
            <Setter Property="Foreground" Value="Green" />
        </Style>
        <Style x:Key="yellow" TargetType="Label">
            <Setter Property="Foreground" Value="Yellow" />
        </Style>
        <Style x:Key="red" TargetType="Label">
            <Setter Property="Foreground" Value="#D00000" />
        </Style>
        <!-- Fonts -->  
        <Style x:Key="verdana" TargetType="Label">
            <Setter Property="FontFamily" Value="Verdana" />
        </Style>
        <!-- Effects -->
        <Style x:Key="shadow" TargetType="Label">
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect ShadowDepth="0" />
                </Setter.Value>
            </Setter>
        </Style>
        <!-- Predefined Combinations -->
        <Style x:Key="h1" TargetType="{x:Type Label}"
               BasedOn="{WPF:CombiStyle Names='size24 royalBlue'}" />
        <Style x:Key="warning" TargetType="{x:Type Label}"
               BasedOn="{WPF:CombiStyle Names='size24 yellow bold shadow'}">
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="BorderBrush" Value="Yellow" />
        </Style>
    </Application.Resources>
</Application>

享受;)

答案 1 :(得分:0)

不幸的是,我对这个问题的理解是这样的,

由于依赖属性,设计时间分辨率似乎在WPF中起作用。由于MarkupExtension不是从依赖对象派生的,因此您的扩展永远不会在设计时进行评估。至于天气这是一个疏忽或故意是有争议的。

可能有另一种方法可以解决这个问题,但会有所不同。创建一个名为MergeStyles的新附加属性。在该属性中,您可以指定要合并和应用的样式名称。更改值时,只需使用上面的代码更新attachee的样式。您可以使用要合并的每个样式的位置来确定层次结构。

这不完全是你想要的,但它可能会让你到达一半。结果就是你可以绑定它。