2013-07-18 12 views
6

überprüfen Sie das folgende Szenario (andere können auch anwenden) [Sie das Projekt nur den Code hier auf der rechten Seite Datei einfügen Kopie erstellen]:Fehler im Visual Studio WPF-Designer?

a - ein Resource mit grundlegenden Sachen (Resources.xaml) anlegen:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 

    <SolidColorBrush Color="Red" x:Key="Test" /> 

    <Style TargetType="{x:Type GroupBox}" x:Key="Test2" > 
     <Setter Property="Background" Value="Blue" /> 
    </Style> 

    <Style TargetType="{x:Type TextBlock}" > 
     <Setter Property="Foreground" Value="Green" /> 
    </Style> 
</ResourceDictionary> 

b - erstellen Sie ein Benutzersteuerbasis, wo andere werden mit basischer Ressource (UserControlBase.cs) erben:

using System.Windows.Controls; 
using System; 
using System.Windows; 

namespace ResourceTest 
{ 
    public class UserControlBase : UserControl 
    { 
     public UserControlBase() 
     { 
      this.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("ResourceTest;component/Resources.xaml", UriKind.RelativeOrAbsolute) }); 
     } 
    } 
} 

c - erstellen Sie ein Benutzersteuerelement von der Basis vererben (UserControl1.xaml):

<ResourceTest:UserControlBase x:Class="ResourceTest.UserControl1" 

      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:ResourceTest="clr-namespace:ResourceTest" 

      mc:Ignorable="d" 

      d:DesignHeight="300" 
      d:DesignWidth="300" > 
    <Grid> 
     <GroupBox BorderBrush="{StaticResource Test}" Margin="3" Header="Test" Style="{DynamicResource Test2}" > 
      <TextBlock Text="TESTTEST" /> 
     </GroupBox> 

    </Grid> 
</ResourceTest:UserControlBase> 

Ergebnisse: StaticResources nicht aufgelöst werden (und der Test-BorderBrush nicht geladen). DynamicResources sind aufgelöst (der Hintergrund ist blau), aber der Designer sagt, dass er die Ressource trotzdem nicht finden kann (das erste Mal funktioniert in Ordnung, aber wenn Sie den Designer öffnen/schließen, kann die Ressource nicht aufgelöst werden). Nicht benannte Ressourcen wie der TextBlock-Stil funktionieren einwandfrei.

Ist das ein Designerfehler oder mache ich etwas falsch? Ist es in Ordnung, die Ressourcen in einem Szenario als dynamisch zu deklarieren, in dem sich die Ressourcen niemals ändern?

enter image description here

Vielen Dank im Voraus.

+0

Es ist in Ordnung, Ressourcen als dynamisch zu deklarieren, nur nicht so effizient. Wenn Sie dieses ResourceDictionary nur hier verwenden, haben Sie versucht, es in 'UserControl.Resources' in einer XAML-Front für die Basisklasse hinzuzufügen, um festzustellen, ob es sich anders verhält? –

+0

@WillEddins: In meiner realen Anwendung werden die Ressourcen auf einem Basis - UserControl gesetzt, so dass jedes Steuerelement über die erforderlichen Ressourcen verfügt, um es direkt im WPF - Designer anzuzeigen (andernfalls werden die Stile nur zur Laufzeit angewendet und wir können erst dann das richtige UI - Design erstellen) App bei jedem Wechsel: S). –

Antwort

1

Es scheint, dass der Designer Schwierigkeiten hat, MergedDictionaries zu lösen, die im Code-Behind zur Entwurfszeit definiert sind.

Ein noch schlimmeres Beispiel kann gesehen werden, indem Sie die ResourceDictionary vor Ihre Initialize verschieben.

public UserControl1() 
{ 
    this.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("TempProject;component/Resources.xaml", UriKind.RelativeOrAbsolute) }); 
    InitializeComponent(); 
} 

In diesem Fall schlägt die DynamicResource auch zur Entwurfszeit zu lösen, wird die Entwurfszeitansicht, die nicht unbedingt die Konstrukteurs-Aufruf, wie man erwarten kann. Ich habe das mit Visual Studio 2012 getestet, also hat sich dieses Verhalten seit 2010 nicht geändert.

in Bezug auf Ihre ursprüngliche Test-Code, beachten Sie, dass die StaticResource erfolgreich wie erwartet zur Laufzeit (der rote Rand erscheint), unabhängig des "error" und des Fehlens eines roten Rahmens durch die Entwurfszeitansicht.

Ich sehe zwei Möglichkeiten:

  1. Verwendung DynamicResource wo notwendig, diese zu Entwurfszeit zu lösen. Während Sie StaticResource verwenden können, würden die damit verbundenen "Fehler" und fehlende Entwurfszeit-Ansicht eindeutig ein Problem sein. Other answers seem to indicate there may not be much performance difference zwischen den beiden jetzt.

  2. Einfach das ResourceDictionary in Ihrem UserControl.Resources instanziieren und nicht von einer Basisklasse erben. Während Sie mit einer Basisklasse ein wenig Code verdichten, sind Sie nicht effizienter, da immer eine neue ResourceDictionary Instanz erstellt wird. Da Sie (AFAIK) nicht von einer Basisklasse mit einem XAML-Frontend ausgehen können, könnten Sie möglicherweise dagegen argumentieren, dass Sie auf dieser Abstraktionsebene eine unreferenzierte MergedDictionary haben.

+0

Vielen Dank für die Zeit, die Sie hier verbracht haben. Wir verwenden derzeit Ansatz 1, aber ich bin ein bisschen besorgt wegen der Warnung (auch wenn es nicht schadet, sollte es nicht da sein). Lösung 2 ist keine Option, da die Ressourcen der Basisklasse ein wenig komplex sind (Sie können den Stil der Anwendung zur Laufzeit ändern), so dass mehrere Ressourcenwörterbücher beteiligt sind. Um die Dinge schwieriger zu machen, wollen wir die Steuerelemente zur Designzeit wie in Runtime sehen, so dass wir die Resourcedictionaries nur zur Designzeit hinzufügen (ansonsten kommen sie aus der App). Deshalb haben wir eine Basis UserControl ... –

+0

Denkst du, dass wir einen Fehler an Frau schicken sollten? –

+0

@SoMoS Ich wäre daran interessiert, von jemandem zu hören, der besser mit der Funktionsweise des Konstrukteurs in Bezug auf Konstruktoraufrufe und dergleichen vertraut ist. In Bezug auf die Änderung des Stils zur Laufzeit würde ich normalerweise erwarten, dass ein 'ResourceDictionary' auf der Ebene 'Application.Resources' geändert wird. Selbst wenn Sie das 'ResourceDictionary' in dem Beispiel als statisch definiert haben (also wenn es hinzugefügt wird), müssen Sie das MergedDictionary immer pro Instanz ändern, oder? Ich bin mir sicher, dass Ihre Implementierung anders ist, aber es scheint ein komplizierter Weg zu sein. –