如何在Blend/VS中获得所见即所得的设计,而不需要在每个XAML文件中合并ResourceDictionary?

8

我刚刚解决了一个很大的内存问题,我以前在每个xaml文件中合并我们的“主题”资源字典,而不仅仅是在app.cs.xaml中。

但是,在除App.cs.xaml之外的每个文件中删除合并后,我失去了设计时样式/模板。

请注意:这仅适用于合并到我们的Themes.xaml中的样式(例如Color.xaml,Brushes.xaml-我们每种类型都有一个)。直接在Themes.xaml中定义的内容(我们没有...)有效。

我看到两个解决方案,

1)在XAML中注释掉合并,并在想要使用设计时的时候取消注释。

2)将其放在每个控件的默认ctor中:(可能仅在Blend中有效)

#if DEBUG
Resources.MergedDictionaries.Add(
                new ResourceDictionary()
                {
                    Source = new System.Uri(@"RD.xml")
                }
                );
#endif

有没有更好的方法来获得页面和控件的设计时编辑?有人知道吗?

谢谢!

6个回答

10

Blend 4支持“设计时资源”,这也是Visual Studio 2010所支持的。请参见http://adamkinney.wordpress.com/2010/05/04/design-time-resources-in-expression-blend-4-rc/

它基本上就是一个包含任何你喜欢的MergedDictionaries的ResourceDictionary,并在项目文件中显示如下(由Blend自动添加):

<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
  <Generator>MSBuild:Compile</Generator>
  <SubType>Designer</SubType>
  <ContainsDesignTimeResources>true</ContainsDesignTimeResources>
</Page>

非常好用。


3
这绝对是此页面上最好的答案。非常感谢,帮助巨大。 - cunningdave
1
我发现如果ResourceDictionary在同一个项目中,这种方法非常有用。然而,在Blend 4中,我无法让它在ResourceDictionary位于不同项目的情况下工作。对于这些情况,我不得不采用这种方法 - Jason Frank
SCOBI,你是王者!我寻找这个解决方案已经...几年了吗?非常感谢! - okieh

8
我所做的是添加一个继承自ResourceDictionary的类,并覆盖源属性以检查IsInDesignMode是否为真。
如果是这样,我就设置源,否则我将源留空(这实际上防止了字典在运行时合并)。
public class BlendMergedDictionary : ResourceDictionary
{
    public bool IsInDesignMode
    {
        get
        {
            return (bool)DependencyPropertyDescriptor.FromProperty(
                            DesignerProperties.IsInDesignModeProperty,
                            typeof(DependencyObject)
                            ).Metadata.DefaultValue;
        }
    }

    public new Uri Source
    {
        get { return base.Source; }
        set
        {
            if (!IsInDesignMode)
                return;

            Debug.WriteLine("Setting Source = " + value);
            base.Source = value;
        }
    }
}

现在,当我需要在Blend中引用字典时,我会像这样合并字典。

<ResourceDictionary.MergedDictionaries>
            <BlendHelpers:BlendMergedDictionary Source="Foo.xaml" />
</ResourceDictionary.MergedDictionaries>

你仍然需要在每个文件中“合并”字典,但你不必承担实际运行时加载字典的惩罚。合并只是为了支持设计时行为。


1
顺带一提,混合字典在 Blend 中无法工作的原因是相对路径问题。当 Blend 托管您的应用程序时,它会将其放置在自己的目录中(Blend.exe 安装的位置)。当 Blend 在寻找您的相对路径字典时,它将从自己的目录开始向下查找树形结构。当然,在那里它找不到您的字典,所以会出现错误。 - Brad Cunningham

1

Jane的问题实际上与这个有关,我也遇到了同样的问题。我已经按照Foovanadil的建议创建了ResourceDictionary的子类,但是在设计时会抛出“Uri前缀未被识别”的异常。

即使所有子类所做的只是分配ResourceDictionary的base.Source属性,我仍然会收到此错误。如果我用常规的ResourceDictionary替换我的自定义ResourceDictionary,它就可以正常工作,因此我猜测cider设计师做了一些特殊的事情,可能是用其他东西替换了ResourceDictionary。

我还没有在Blend中尝试过这个,但我在VS2010(sp1 beta)中确实遇到了这个问题。有人能确认发布的答案在vs2010中是否有效吗?

-编辑-

有可能是基于wpf的设计师在资源定位逻辑方面出了问题。我在其他地方读到,pack uri是基于“执行”程序集而不是“本地”程序集的。我会报告我找到的内容

-编辑2/解决方案-

好的,我成功地在VS2010中使用了Foovanadil解决方案,这是个交易。结果证明我是对的一半,可能是因为VS2010中的wpf设计师本身就是用wpf编写的,或者为了提供更好的设计体验,ResourceDictionary(或者VS2010使用的其他类)在设计时表现不同。

事实证明,VS替换了在xaml中输入的URI。连接到VS实例并在Source的setter中设置断点会发现实际传递的值与我们期望的值不同。

给定xaml:

<Window.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <local:DesignTimeResourceDictionary Source="myxamlfile.xaml"  />
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Window.Resources>

Source已设置为

markup://1/file:///c:/PathtoMyapp/MainWindow.xaml#0/myxamlfile.xaml

而不是

/myxamlfile.xaml

这就是为什么我们会得到无效URI异常的原因。

关于VS2010在设计时如何编辑URI以及何时编辑,我并不清楚,但是将DesignTimeResourceDictionary中的Source属性重命名为其他名称并不能解决问题。

幸运的是,有一个解决方法。如果我们将Source的类型从Uri更改为String,则VS设计器不会修改该值。在setter中,我们创建一个Uri并将其传递给基本属性:

public new String Source {
  get {
    return base.Source.ToString();
  }
  set {
    if( !IsInDesignMode )
      return;
    base.Source = new Uri( value, UriKind.RelativeOrAbsolute );
  }
}

请注意,如果您使用此方法(或任何其他我发现的方法,例如在资源文件中使用x:class并直接从xaml实例化),将导致样式在构建之前不会更新。使用标准的ResourceDictionary将导致设计师在编辑导入的资源文件后立即更新(甚至在保存之前)。这也表明设计师在设计时以不同的方式处理ResrouceDictionary。

希望有人会发现这个有用 :)


0

另一种方法(我们现在采用的方法):使用预构建脚本注释掉所有XAML文件中的合并。

这样做会使在DEBUG模式下调试内存问题等变得更加困难,但可以完全自动化,并解决最终发布的问题。


0

脚本的想法对我来说似乎不是个好主意。你的源代码控制中会有很多“虚假”的修订版本,我的猜测是你需要花费大量时间进行微调。

我一直希望VS2010和Expression Blend 3在这方面有大的改进。有人试用过beta版并知道吗?


0

你可以在App.xaml的资源中添加资源字典,这对我来说非常完美。 或者可能是我没有理解你的意思。


不是上次我在这个应用程序上测试过了吗?让我再试一次,然后回报结果。 - andyhammar
好的,经过进一步调查,我已经确定了问题所在:在app.xaml中使用普通RD可以正常工作,但合并的字典却不行。我现在会更新主要问题。 - andyhammar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接