XAML 是不是有用于调试模式的条件编译器指令?

Posted

技术标签:

【中文标题】XAML 是不是有用于调试模式的条件编译器指令?【英文标题】:Does XAML have a conditional compiler directive for debug mode?XAML 是否有用于调试模式的条件编译器指令? 【发布时间】:2012-02-02 16:12:54 【问题描述】:

对于 XAML 中的样式,我需要这样的东西:

<Application.Resources>

#if DEBUG
    <Style TargetType="x:Type ToolTip">
        <Setter Property="FontFamily" Value="Arial"/>
        <Setter Property="FlowDirection" Value="LeftToRight"/>
    </Style>
#else
    <Style TargetType="x:Type ToolTip">
        <Setter Property="FontFamily" Value="Tahoma"/>
        <Setter Property="FlowDirection" Value="RightToLeft"/>
    </Style>
#endif

</Application.Resources>

【问题讨论】:

我需要在调试模式下有不同的风格,这样我才能在调试模式下更轻松地执行。 【参考方案1】:

我最近不得不这样做,当我无法轻松找到任何明确的示例时,我对它的简单程度感到惊讶。我所做的是将以下内容添加到 AssemblyInfo.cs:

#if DEBUG
[assembly: XmlnsDefinition( "debug-mode", "Namespace" )]
#endif

然后,使用 markup-compatability 命名空间的 AlternateContent 标签根据该命名空间定义的存在来选择您的内容:

<Window x:Class="Namespace.Class"
        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="debug-mode"

        Width="400" Height="400">

        ...

        <mc:AlternateContent>
            <mc:Choice Requires="d">
                <Style TargetType="x:Type ToolTip">
                    <Setter Property="FontFamily" Value="Arial"/>
                    <Setter Property="FlowDirection" Value="LeftToRight"/>
                </Style>
            </mc:Choice>
            <mc:Fallback>
                <Style TargetType="x:Type ToolTip">
                    <Setter Property="FontFamily" Value="Tahoma"/>
                    <Setter Property="FlowDirection" Value="RightToLeft"/>
                </Style>
            </mc:Fallback>
        </mc:AlternateContent>

        ...
</Window>

现在,当定义 DEBUG 时,“debug-mode”也将被定义,并且“d”命名空间将出现。这使得 AlternateContent 标记选择第一个代码块。如果未定义 DEBUG,则将使用 Fallback 代码块。

此示例代码未经测试,但它与我在当前项目中用于有条件地显示一些调试按钮的基本相同。

我确实看到了一篇博客文章,其中包含一些依赖于“Ignorable”标签的示例代码,但这种方法似乎不太清晰且易于使用。

【讨论】:

VS 错误窗格不喜欢这样,尽管一切都按预期工作:link 将代码添加到 AssemblyInfo.cs 时,我的解决方案无法编译。我得到The type or namespace name 'XmlnsDefinitionAttribute' could not be found (are you missing a using directive or an assembly reference?)。我能做什么? XmlnsDefinitionAttributeSystem.Windows.Markup 命名空间中。此命名空间位于System.Xaml.dll 程序集中,我相信它是在您在 Visual Studio 中创建 WPF 项目时自动添加的。 请注意,您可能需要将“mc”标记为可忽略自身,即 mc:Ignorable="d mc" 知道为什么在 Xamarin 中我收到此错误Type mc:Choice not found in xmlns http://schemas.openxmlformats.org/markup-compatibility/2006【参考方案2】:

这在 WPF/Silverlight/WP7 中是不可能的。

有趣的是,标准文档ISO/IEC 29500(Office Open XML 文件格式)介绍了如何在 XML 文档中处理这些内容,并且 XAML 确实支持以下项目之一该规范mc:Ignorable 允许我们做这样的事情:

<Page xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:c="Comments"
      mc:Ignorable="c">
    <Button Content="Some Text"
            c:Content="Some other text" />
</Page>

注释掉属性。

XAML 解析器团队(SL4、WP7.1、WPF)选择使用该规范来解决他们忽略属性的需求,而不仅仅是编造一些东西。这就是为什么某些默认 XAML 页面定义了“mc”命名空间的原因。我确实认为,如果 XAML 有朝一日支持允许加载替代内容的其余规范,那会很酷。

Blend 使用mc:Ignorable 属性来支持设计时功能。

【讨论】:

【参考方案3】:

您可以使用模板选择器。 DataTemplateSelector 类是您编写的代码。使用您覆盖的模板选择方法,您可以放置​​您的预处理器指令。

http://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector.aspx

【讨论】:

如果问题是关于备用查看内容,则DataTemplateSelector 可能是相关的,但它是关于备用样式 - 没有“选择器" 用于替代样式。好吧,您可以创建两个单独的内容副本,使用不同的样式……但这听起来不像您在这里要说的。【参考方案4】:

我对其中任何一个都不满意,于是做了这个:

在我的 XAML 中,我将任何属性或标签都放在一个空格中,这样我就知道我在 .cs 文件中搞砸了。

<Window x:Class="...
    mc:Ignorable="d"
    Title="" 
    BorderThickness="2"
    WindowStartupLocation="CenterScreen"
    ResizeMode="NoResize"
    Height="200" 
    Width="500"
    
    WindowStyle="None"    
    >

然后在我后面的代码中我这样做:

    public partial class ScanProgressWindow : Window
    
        public ScanProgressWindow()
        
            InitializeComponent();
 #if DEBUG
            this.WindowStyle = WindowStyle.SingleBorderWindow;
 #endif
        
    

为我工作。

【讨论】:

【参考方案5】:

我觉得给定的答案并不是最容易使用的。这是我使用自定义可附加依赖属性的解决方案:

using namespace Utility
    public static class DebugVisibility
    
        public static readonly DependencyProperty IsVisibleProperty = DependencyProperty.RegisterAttached(
    "Debug", typeof(bool?), typeof(DebugVisibility), new PropertyMetadata(default(bool?), IsVisibleChangedCallback));

        private static void IsVisibleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var fe = d as FrameworkElement;
            if (fe == null)
                return;
#if DEBUG
            fe.Visibility = Visibility.Visible;
#else
            fe.Visibility = Visibility.Collapsed;
#endif
        

        public static void SetIsVisible(DependencyObject element, bool? value)
        
            element.SetValue(IsVisibleProperty, value);
        

        public static bool? GetIsVisible(DependencyObject element)
        
            return (bool?)element.GetValue(IsVisibleProperty);
        
    

xaml 会像这样使用:

<window ... xmlns:Util="clr-namespace:MyNamespace.Utility" >
    <Label Util:DebugVisibility.IsVisible="True">
</window>

我将其保留为布尔值,以防您想在其中添加一些其他可见性逻辑。这是一个不错的简单切换,可以绑定和附加到任何控件

【讨论】:

好主意,但实现可以简单得多。 Debug/Release 显然在运行过程中不会改变,所以你不需要所有的 Binding/Dependency 东西。你所需要的只是 Util 中的一个静态变量“Debug”,即 Debug 时为 True,否则为 False。 (为方便起见,第二个静态“Release”在调试时为 False。)然后执行&lt;Label IsVisible=Static Util:Debug 注意:此答案与“条件编译”不同; IsVisible=False 表示创建了视图对象(尽管没有布局调用)。这有一些成本,尽管通常是很小的成本——所以对于某些目的来说是可以的。 对于这个特定问题没有用,这是关于替代 styles - IsVisible 在那里没有帮助。 顺便说一句,如果您的代码基于您在其他地方看到的示例,您应该提供一个链接来感谢其代码帮助您创建此代码的作者。正如here 所提到的,看起来很复杂,因此 VS 设计师可以看到这种变化;如果这就是复杂性的原因,那么您应该提到这一点。

以上是关于XAML 是不是有用于调试模式的条件编译器指令?的主要内容,如果未能解决你的问题,请参考以下文章

C编译器中是不是有调试模式编译标志的标准?

编译器指令 - 建议 - 仅在调试模式下运行代码

DTrace pid 提供程序是不是仅适用于调试模式编译的程序?

调试 GNU make

对条件属性使用编译器指令

Xcode Debug 指令,不污染源码的添加判断的调试方式