WPF 和 XAML 的隐藏特性?

Posted

技术标签:

【中文标题】WPF 和 XAML 的隐藏特性?【英文标题】:Hidden features of WPF and XAML? 【发布时间】:2010-11-10 14:52:10 【问题描述】:

这里有大量针对各种语言讨论的隐藏功能。现在我很好奇 XAML 和 WPF 的一些隐藏特性?

我发现的一个是 ListView 的标题点击事件

<ListView x:Name='lv' 
      Height="150" 
      GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">

GridViewColumnHeader.Click 属性未列出。

目前的一些相关功能:

Multibinding combined with StringFormat

TargetNullValue to bindings

TextTrimming property

Markup extensions

Adding Aero effect to Window

Advanced "caption" properties

XAML Converters

另请参阅:

    Hidden features of C# Hidden features of Python Hidden features of ASP.NET Hidden features of Perl Hidden features of Java Hidden features of VB.NET Hidden features of php Hidden features of Ruby Hidden features of C And So On........

【问题讨论】:

看看这里msdn.microsoft.com/en-us/library/…。 click 事件继承自 ButtonBase。您所描述的是附加事件,这是 WPF 中一个非常强大的概念 (msdn.microsoft.com/en-us/library/bb613550.aspx)。这样,您可以在网格上使用 100 个按钮并且只有 1 个处理程序来执行 起初我就像“哦,我们又来了”,但后来我从回复中学到了一些东西,所以我把它全部收回:o:o 应该是社区维基 @tsilb 我不认为它应该是社区维基,看看这个链接meta.stackexchange.com/questions/392/… 【参考方案1】:

3.5sp1 将 StringFormat 引入绑定表达式,例如

<TextBox Text="Binding Date, StringFormat='0:MM/dd/yyyy'" />

【讨论】:

我无法用语言表达我对这个功能的喜爱程度。我讨厌有大量的价值转换器。 是的,很容易添加最节省时间的功能之一。尤其是与 TargetNullValue 结合使用时,很多问题都会消失。 在 StringFormat 周围加上单引号应该可以消除一些编译器警告 - Text=Binding Date, StringFormat='0:MM/dd/yyyy'" 很高兴知道,我已经习惯了忽略它们。 我试图传达任何任意格式的字符串都可以工作。我相信在这种情况下,国际化版本将是 StringFormat='0:d'。【参考方案2】:

Multibinding(结合StringFormat):

<TextBlock>
  <TextBlock.Text>
    <MultiBinding StringFormat="0, 1">
      <Binding Path="LastName" />
      <Binding Path="FirstName" />
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

【讨论】:

太棒了 :-) 除非您使用的是 silverlight 4 或更早版本。为 v5 祈祷 这很好,但我很想不这样做。如果我需要构建一个字符串,我会将其归类为逻辑并希望对输出进行单元测试。像这样的东西有时在视图模型中作为 string.Format() 更好。【参考方案3】:

3.5sp1 将 TargetNullValue 引入绑定。如果输入了值,这会将绑定属性设置为 Null,如果您的属性为 Null,它将显示此值。

<TextBox Text="Binding Total, TargetNullValue=$0.00" />

【讨论】:

【参考方案4】:

网格大小共享(here's 一个很好的例子)。长话短说,您可以让网格列和行共享大小,甚至跨不同的网格。这对于所有使用 DataGrids 而无需就地编辑数据的人来说将是无价的。

【讨论】:

【参考方案5】:

还有 PresentationTraceSources.TraceLevel 技巧来调试在任何特定场景中绑定的情况。您所要做的就是在 WindowsBase 程序集中引用 System.Diagnostics 命名空间

xmlns:sd="clr-namespace:System.Diagnostics;assembly=WindowsBase"

然后在绑定表达式中添加以下内容:

<TextBlock Text="Binding Message, sd:PresentationTraceSources.TraceLevel=High"  />

日志会是这样的:

System.Windows.Data Warning: 52 : Created BindingExpression (hash=5923895) for Binding (hash=7588182)
System.Windows.Data Warning: 54 :   Path: 'Message'
System.Windows.Data Warning: 56 : BindingExpression (hash=5923895): Default mode resolved to OneWay
System.Windows.Data Warning: 57 : BindingExpression (hash=5923895): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 58 : BindingExpression (hash=5923895): Attach to System.Windows.Controls.TextBlock.Text (hash=65248697)
System.Windows.Data Warning: 63 : BindingExpression (hash=5923895): Resolving source 

【讨论】:

在 VisualStudio 2010 中,您需要将跟踪设置的级别设置为警告!见***.com/questions/2802662/…【参考方案6】:

不是真正的隐藏功能,但使用 WPF/XAML,您会得到 Bea Stollnitz 和 Josh Smith。 WPF/XAML 编程的女王和王者。

【讨论】:

什么是卡尔?千斤顶?还是小丑?【参考方案7】:

高级“字幕”属性

还有一点不是很清楚,就是我们习惯的一些属性的内容只包含文本。如果 GUI 元素的属性是 Object 类型,那么您很可能可以添加一个包含一组控件的面板,而不仅仅是设置文本。

MenuItem 就是一个例子,其中Header 属性(通常只包含文本)可以包含一组封装在面板控件中的 gui 元素(或者如果您只需要一个 gui 元素,则只包含一个 gui 元素)。

还要注意 MenuItem 上的 Icon 属性。这通常包含一个 Image 元素,但它也可以包含任何东西!

<MenuItem Name="MyMenuItem" Click="MyMenuItem_Click">
  <MenuItem.Icon>
    <Button Click="Button1_Click">i</Button>
  </MenuItem.Icon>
  <MenuItem.Header>
     <StackPanel Orientation="Horizontal" >
        <Label>My text</Label>
        <Button Click="Button2_Click">ClickMe!</Button>
     </StackPanel>
  </MenuItem.Header>
</MenuItem>

【讨论】:

【参考方案8】:

标记扩展和附加属性是我最喜欢的功能,它们使您能够以一种非常优雅的方式扩展 XAML“词汇表”。

标记扩展

<!-- Binding to app settings -->
<CheckBox IsChecked="my:SettingBinding MinimizeToTray">Close to tray</CheckBox>

<!-- Fill ItemsControl with the values of an enum -->
<ComboBox ItemsSource="my:EnumValues sys:DaysOfWeek"/>

<!-- Localization -->
<TextBlock Text="my:Localize HelloWorld.Text"/>

<!-- Switch on the result of a binding -->
<TextBlock Text="my:Switch Path=IsGood, ValueIfTrue=Good, ValueIfFalse=Bad"/>

附加属性

<!-- Sort GridView automatically -->
<ListView ItemsSource="Binding Persons"
      IsSynchronizedWithCurrentItem="True"
      util:GridViewSort.AutoSort="True">
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Name"
                                DisplayMemberBinding="Binding Name"
                                util:GridViewSort.PropertyName="Name"/>
                <GridViewColumn Header="First name"
                                DisplayMemberBinding="Binding FirstName"
                                util:GridViewSort.PropertyName="FirstName"/>
                <GridViewColumn Header="Date of birth"
                                DisplayMemberBinding="Binding DateOfBirth"
                                util:GridViewSort.PropertyName="DateOfBirth"/>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>


<!-- Vista Glass effect -->
<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication1"
        Title="Window1"
        my:WinUtil.EnableAeroGlass="True">

...

GridViewSort 的来源(顺便说一句,它使用了 Ortus 提到的 GridViewColumnHeader.Click 事件)

【讨论】:

WinUtil.EnableAeroGlass 的来源是否在某处可用? 是的,但自从我发布此内容后,它发生了很大变化……现在有 2 个属性,EnableBlur 和 GlassFrameMargins。你可以在这里找到代码:projets.developpez.com/projects/dvp-net/repository/entry/trunk/…【参考方案9】:

给窗口添加 Aero 效果

  <Window.Resources>
    <ResourceDictionary Source="/PresentationFramework.Aero, Version=3.0.0.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL;component/themes/aero.normalcolor.xaml" />
</Window.Resources>

【讨论】:

添加了代码,但仍然没有添加 Aero 效果。我错过了什么吗?【参考方案10】:

有时你得到的字符串太长而无法在标签上显示。在这种情况下,我们可以利用 TextBlockTextTrimming 属性来显示椭圆

<TextBlock 
  Name="sampleTextBlock" 
  TextTrimming="WordEllipsis" 
  TextWrapping="NoWrap"/>

MSDN Link

【讨论】:

考虑在这种情况下添加工具提示:tranxcoder.wordpress.com/2008/10/12/…【参考方案11】:

在禁用的控件上显示工具提示

如果控件处于禁用状态,Wpf 允许在控件上显示工具提示。

例如

<Button Content="Disabled Button" ToolTipService.ShowOnDisabled="True" IsEnabled="False" ToolTip="This is a disabled button"/> 

【讨论】:

【参考方案12】:

内置类型

如果您想将字符串或双精度等简单类型的对象添加到资源字典中,您需要将所需的 clr 命名空间映射到 XML 命名空间。在 XAML 2009 中,我们在 XAML 语言中包含了很多简单类型。

<!-- XAML 2006 -->
<sys:String xmlns:sys="clr-namespace:System;assembly=mscorlib >Test</sys:String>

<!-- XAML 2009 -->
<x:String>Test</x:String>

以下类型包含在 XAML 语言中:

<x:Object/> 
<x:Boolean/> 
<x:Char/> 
<x:String/> 
<x:Decimal/> 
<x:Single/> 
<x:Double/> 
<x:Int16/> 
<x:Int32/> 
<x:Int64/> 
<x:TimeSpan/> 
<x:Uri/> 
<x:Byte/> 
<x:Array/> 
<x:List/> 
<x:Dictionary/> 

【讨论】:

如果使用 WPF 处理 XAML,这将不起作用。 msdn.microsoft.com/en-us/library/ee792007.aspx【参考方案13】:

通过 x:FactoryMethod 使用静态工厂方法

当您有一个没有公共构造函数但有静态工厂方法的类型时,您必须在 XAML 2006 的代码中创建该类型。使用 XAML 2009,您可以使用 x:FactoryMethodx:Arguments 属性来传递参数值。

<!-- XAML 2006 -->
Guid id = Guid.NewGuid();

<!-- XAML 2009 -->
<Guid x:FactoryMethod="Guid.NewGuid" />

【讨论】:

【参考方案14】:

支持任意字典键

在 XAML 2006 中,所有显式 x:Key 值都被视为字符串。在 XAML 2009 中,您可以通过在 ElementSyntax 中编写键来定义您喜欢的任何类型的键。

<!-- XAML 2006 -->
<StreamGeometry x:Key="CheckGeometry">M 0 0 L 12 8 l 9 12 z</StreamGeometry>

<!-- XAML 2009 -->
<StreamGeometry>M 0 0 L 12 8 l 9 12 z
    <x:Key><x:Double>10.0</x:Double></x:Key>
</StreamGeometry>

【讨论】:

【参考方案15】:

使用 x:Reference 的简单对象引用

如果您今天想创建一个对象引用,您需要进行数据绑定并使用 ElementName 声明源。在 XAML 2009 中,您可以使用新的 x:Reference 标记扩展

<!-- XAML 2006 -->
<Label Target="Binding ElementName=firstName">FirstName</Label>
<TextBox x:Name="firstName" />

<!-- XAML 2009 -->
<Label Target="x:Reference firstName">FirstName</Label>
<TextBox x:Name="firstName" />

【讨论】:

值得注意的是,虽然x:Reference 是 XAML 2009 语言功能,但在某些情况下它也适用于编译后的 XAML。但是,它并不适用于所有地方,并且可能会破坏 XAML 设计器视图。 @MikeStrobel:它几乎在任何地方都有效,而且我不在乎设计师的破坏。【参考方案16】:

通过 x:Arguments 使用非默认构造函数

在 XAML 2006 中,对象必须具有公共默认构造函数才能使用它们。在 XAML 2009 中,您可以使用 x:Arguments 语法传递构造函数参数。

<!-- XAML 2006 -->
<DateTime>00:00:00.0000100</DateTime>

<!-- XAML 2009 -->
<DateTime>
    <x:Arguments>
        <x:Int64>100</x:Int64>
    </x:Arguments>
</DateTime>

【讨论】:

【参考方案17】:

XAML 中的泛型与 x:TypeArguments

如果你想在 XAML 中使用 ObservableCollection,你需要创建一个派生自 ObservableCollection 的类型,因为你不能在 XAML 中声明它。在 XAML 2009 中,您可以使用 x:TypeArguments 属性来定义泛型类型的类型。

<!-- XAML 2006 -->
class EmployeeCollection : ObservableCollection<Employee>



<l:EmployeeCollection>
    <l:Employee FirstName="John" Name="Doe" />
    <l:Employee FirstName="Tim" Name="Smith" />
</lEmployeeCollection>

<!-- XAML 2009 -->
<ObservableCollection x:TypeArguments="Employee">
    <l:Employee FirstName="John" Name="Doe" />
    <l:Employee FirstName="Tim" Name="Smith" />
</ObservableCollection />

【讨论】:

不幸的是,x:TypeArguments 仅在松散的 xaml 文件中可用,而在编译的文件中不可用:( 是的,只有松散的 xaml :( 对于大多数 WPF 开发人员来说,XAML2009 是无用的。【参考方案18】:

通过代码设置 ValidationError

BindingExpression 中的 ValidatioRule 仅在绑定的目标端发生更改时触发。如果你想通过代码设置验证错误可以使用下面的sn-p。

设置验证错误

ValidationError validationError = 
    new ValidationError(regexValidationRule, 
    textBox.GetBindingExpression(TextBox.TextProperty));

validationError.ErrorContent = "This is not a valid e-mail address";

Validation.MarkInvalid(
    textBox.GetBindingExpression(TextBox.TextProperty), 
    validationError);

清除验证错误

Validation.ClearInvalid(textBox.GetBindingExpression(TextBox.TextProperty));

【讨论】:

【参考方案19】:

XAML 转换器

以下列表显示了 WPF 社区开发的转换器,用于将不同格式转换为 XAML,反之亦然。

Adobe Illustrator XAML Export Plugin

Adobe Photoshop to XAML Converter

Blender XAML Export Plugin

Lightwave XAML Export Plugin

Visio XAML Export

3D Studio Max to XAML Converter

Maya to XAML Converter

Flash to XAML Converter

SVG to XAML Converter

WMF/EMF to XAML Converter

【讨论】:

也很有用:GridLengthConverter, BooleanToVisibilityConverter, AlternationConverter all in System.Windows.Controls【参考方案20】:

调试动画

常见错误

如果您收到以下错误:Cannot animate '(0).(1)' on an immutable object instance。可能是您遇到了以下限制之一:

您正在为依赖属性设置动画而没有设置本地值 您正在为一个依赖属性设置动画,该属性的当前值是在另一个未合并到资源字典中的程序集中定义的。 您正在为当前数据绑定的值设置动画

【讨论】:

【参考方案21】:

PriorityBinding。允许您以“先到先显示”的顺序使用异步绑定:

<TextBlock.Text>
      <PriorityBinding FallbackValue="defaultvalue">
        <Binding Path="SlowestDP" IsAsync="True"/>
        <Binding Path="SlowerDP" IsAsync="True"/>
        <Binding Path="FastDP" />
      </PriorityBinding>
</TextBlock.Text>

【讨论】:

【参考方案22】:

系统颜色使用

<Border Background="DynamicResource x:Static SystemColors.InactiveBorderBrushKey"/>

【讨论】:

将其指定为 DynamicResource 很重要,因为用户可以在应用程序运行时更改系统颜色。【参考方案23】:

您可以使用加号 (+) 在 XAML 中引用嵌套类型。例如,如果我们有这个类:

public class SomeClass

    public enum SomeEnum
    
        SomeValue
    ;

我们可以使用以下语法在 XAML 中引用 SomeValue

x:Static local:SomeClass+SomeEnum.SomeValue

这个语法是not documented on MSDN,官方不支持。有人在 MSDN 论坛上asked about it,显然它破坏了 VS2010 的 WPF 设计器。它在 Microsoft Connect 上有 been reported。

【讨论】:

【参考方案24】:

将 UIElement(s) 填充到 TextBlock 中的能力

我不知道这有多有用(虽然它有资格被隐藏)...但是当我first ran into it 时它确实让我措手不及:

<Grid x:Name="LayoutRoot">
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid>
            <Rectangle Fill="AliceBlue" Width="25" Height="25"/>
        </Grid>
    </TextBlock>
</Grid>

您可能认为以下 xaml 可能有用(即在某些文本的末尾放置图形):

<Grid>
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Hello World">
        <TextBlock.Resources>
            <DrawingBrush x:Key="exclamationPoint" Stretch="Uniform">
                <DrawingBrush.Drawing>
                    <DrawingGroup>
                        <DrawingGroup.Children>
                            <GeometryDrawing Brush="#FF375CE2" Geometry="F1 M 7.968,58.164L 0,58.164L 1.914,49.921L 9.882,49.921L 7.968,58.164 Z M 21.796,0L 11.054,42.148L 4.403,42.148L 13.049,0L 21.796,0 Z "/>
                        </DrawingGroup.Children>
                    </DrawingGroup>
                </DrawingBrush.Drawing>
            </DrawingBrush>
        </TextBlock.Resources>
        <Grid>
            <Rectangle Width="100" Height="100" Fill="StaticResource exclamationPoint"/>
        </Grid>
    </TextBlock>
</Grid>

上面的 xaml 呈现如下:

【讨论】:

【参考方案25】:

没有 INotifyPropertyChanged 或 DependencyProperties 的绑定

正如 here 所讨论的,您可以在没有 INotifyPropertyChanged 的​​情况下绑定一个普通的 CLR 对象属性,它可以正常工作

我指的是the Forumpost。

引用:

[...] 如果源对象是普通 CLR 对象并且不实现 INotifyPropertyChanged 接口,WPF 的数据绑定引擎将数据绑定到包装源属性的 PropertyDescriptor 实例。并且数据绑定引擎将尝试通过 PropertyDescriptor.AddValueChanged() 方法订阅属性更改事件。而当目标数据绑定元素改变属性值时,数据绑定引擎会调用 PropertyDescriptor.SetValue() 方法将改变后的值传回源属性,同时会引发 ValueChanged 事件通知其他订阅者(在这种情况下,其他订阅者将是 ListBox 中的 TextBlock。

如果您正在实施 INotifyPropertyChanged,您将完全负责在需要将数据绑定到 UI 的属性的每个设置器中实施更改通知。否则,更改将不会像您期望的那样同步。[...]

这里是另一个 great and detailed article 的主题。

注意这仅在使用绑定时有效。如果您从代码更新值,则更改不会收到通知。 [...]

实现 INotifyPropertyChanged 可能是相当乏味的开发工作。但是,您需要根据 WPF 应用程序的运行时占用空间(内存和 CPU)权衡该工作。 自己实现 INPC 将节省运行时 CPU 和内存

【讨论】:

以上是关于WPF 和 XAML 的隐藏特性?的主要内容,如果未能解决你的问题,请参考以下文章

译Visual Studio 2019 中 WPF & UWP 的 XAML 开发工具新特性

广州.NET社区推荐译Visual Studio 2019 中 WPF & UWP 的 XAML 开发工具新特性

WPF 的 DefaultEventAttribute 有什么作用

WPF中 PropertyPath XAML 语法

WPF属性与特性的映射(TypeConverter)

第1章 为什么创造WPF第2章 XAML揭秘