2013-04-09 8 views
16

ich eine Markup-Erweiterung für WPF geschrieben habe, die michDesign-Zeitprüfung von Markup-Erweiterung Argumenten in WPF-Designer

<!-- 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 }" > 

Es ist eine sehr nützliche Erweiterung erlaubt, zu tun und es funktioniert zur Laufzeit groß. Allerdings zur Entwurfszeit kann ich nicht die Stile angezeigt, dass oder wenn ich falsch und kursiv falsch eingeben sie nicht als StaticResources gefunden werden kann.

Irgendwelche Hacks, die ich tun kann, damit das funktioniert?

Der Quellcode für die Erweiterung ist

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

Excellent. Dies sind die Dinge, die Microsoft hätte tun sollen, anstatt das WheelRT neu zu erfinden. –

+0

Hmmmm +5 auf die Frage und keine Antworten. Etwas, das jeder gerne tun möchte, aber nicht möglich ist! – bradgonesurfing

+1

Ja, ich würde gerne Ihre Erweiterung verwenden! –

Antwort

0

Nein Leider Mein Verständnis des Problems dies ist

Design-Zeitauflösung scheint wegen der Abhängigkeitseigenschaften in WPF zu arbeiten. Da MarkupExtension nicht vom Abhängigkeitsobjekt abgeleitet ist, wird Ihre Erweiterung zur Entwurfszeit nie ausgewertet. Was das Wetter angeht war ein Versehen oder absichtlich fraglich.

Es gibt möglicherweise einen anderen Weg, dies zu lösen, der jedoch etwas anders wäre. Erstellen Sie eine neue angefügte Eigenschaft namens MergeStyles. In dieser Eigenschaft können Sie die Stilnamen angeben, die Sie zusammenführen und anwenden möchten. Wenn der Wert geändert wird, aktualisieren Sie einfach den Stil des Attachees mit Ihrem Code oben. Sie können die Position verwenden, in der jeder Stil zusammengeführt wird, um die Hierarchie zu bestimmen.

Es ist nicht genau das, was Sie wollen, aber es kann Sie auf halbem Weg dorthin bringen. Das Ergebnis ist, dass Sie sich jedoch daran binden können.

+0

Es stellt sich heraus, dass das Problem nicht in der Basisklassennatur der MarkupExtension lag. – Sevenate

+0

Sieht gut aus, ich habe eine Erhöhung für dich hinzugefügt! – McDonnellDean

+0

Danke! Froh, dass Sie es mögen. – Sevenate

3

Update: Screenshots hinzugefügt für VS2012 (funktioniert) und Mischung für VS2012 (funktioniert teilweise: Basis Arten BasedOn-Arten sind nicht richtig aus irgendeinem Grund aufgehoben).

geprüft Auch in VS2013 Vorschau und Mischung für VS2013 Preview - dort funktioniert es teilweise und genau das gleiche wie in Mischung für VS2012. Hoffentlich reparieren sie das in der Veröffentlichung.

Works in VS2012 as good as in VS2010

In Blend for VS2012 it works partionally

Die Sache ist, dass Visual Studio-Designer sehr mögen, wenn das Objekt, das Sie in XAML zu beschreiben versuchen, die öffentliche Standardkonstruktor hat, die es Design-Zeit Instanz dieses Objekt verwenden, um instanziiert.

Ich habe ein wenig Ihre CombistyleExtension.cs Klasse aktualisiert, um dies zu berücksichtigen und Visual Studio 2010 Designer gefällt es jetzt. Blend 4 Designer tun das aber immer noch nicht, sorry.

Werfen Sie einen Blick:

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); 
     } 
    } 
} 

Verwendung dieser Markup-Erweiterung auch nur ein wenig verändert.Wie es war:

BasedOn="{WPF:CombiStyle bold italic }" 

und wie es jetzt:

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

Und nur etwas Zeit zu sparen für Sie hier ein bisschen von XAML copy-paste-run-and-Uhr:

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.x aml:

<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> 

Genießen;)

+0

Nicht mit VS2015 arbeiten – Val