首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WPF设计器中标记扩展参数的设计时检查

问WPF设计器中标记扩展参数的设计时检查
EN

Stack Overflow用户
提问于 2013-04-09 20:54:35
回答 2查看 2.3K关注 0票数 18

我为WPF编写了一个标记扩展,它允许我执行以下操作

代码语言:javascript
复制
<!-- 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 }" >

它是一个非常有用的扩展,在运行时效果很好。然而,在设计时,我看不到应用的样式,或者如果我错误地输入了粗体和斜体,它们可能不会被发现为StaticResources。

我能做些什么来让它工作吗?

该扩展的源代码为

代码语言:javascript
复制
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);
        }

    }
}
EN

回答 2

Stack Overflow用户

发布于 2013-06-13 00:56:43

更新:为VS2012 (工作正常)和Blend for VS2012 (部分工作:基于基础的样式-样式由于某些原因不能正确拾取)添加了屏幕截图。

还在VS2013预览和Blend for VS2013 Preview中检查了它-在那里它的工作方式与用于VS2012的Blend完全相同。希望他们在发布时解决这个问题。

​

​

​

​

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

我已经更新了一点你的CombiStyleExtension.cs类来考虑到这一点,Visual Studio2010设计器现在喜欢它。但是Blend 4 designer还是不支持,抱歉。

看一看:

代码语言:javascript
复制
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);
        }
    }
}

这个标记扩展的用法也有少许改变。它是怎样的:

代码语言:javascript
复制
BasedOn="{WPF:CombiStyle bold italic }"

以及现在是如何实现的:

代码语言:javascript
复制
BasedOn="{WPF:CombiStyle Names='bold italic'}"

为了给你节省一些时间,这里有一些xaml可以复制-粘贴-运行-观察:

MainWindow.xaml

代码语言:javascript
复制
<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

代码语言:javascript
复制
<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>

享受;)

票数 3
EN

Stack Overflow用户

发布于 2013-04-17 19:53:30

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

由于依赖属性的原因,设计时解析似乎可以在WPF中工作。由于MarkupExtension不是从依赖项对象派生的,因此在设计时不会计算您的扩展。至于这是疏忽还是故意,尚有争议。

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

这并不完全是你想要的,但它可能会让你走到一半。这样做的结果是,您可以绑定到它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15902503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档