这是针对各种语言讨论的大量隐藏功能。现在我很好奇 XAML 和 WPF 的一些隐藏特性?
我发现的一个是 ListView 的标题点击事件
<ListView x:Name='lv'
Height="150"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
GridViewColumnHeader.Click 属性未列出。
到目前为止的一些相关功能:
也可以看看:
这是针对各种语言讨论的大量隐藏功能。现在我很好奇 XAML 和 WPF 的一些隐藏特性?
我发现的一个是 ListView 的标题点击事件
<ListView x:Name='lv'
Height="150"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
GridViewColumnHeader.Click 属性未列出。
到目前为止的一些相关功能:
也可以看看:
多重绑定(结合 StringFormat):
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}, {1}">
<Binding Path="LastName" />
<Binding Path="FirstName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
还有 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
3.5sp1 将 StringFormat 引入绑定表达式,例如
<TextBox Text="{Binding Date, StringFormat='{}{0:MM/dd/yyyy}'}" />
3.5sp1 将 TargetNullValue 引入绑定。如果输入了值,这会将绑定属性设置为 Null,如果您的属性为 Null,它将显示此值。
<TextBox Text="{Binding Total, TargetNullValue=$0.00}" />
有时你得到的字符串太长而无法在标签上显示。在这种情况下,我们可以利用 的TextTrimming
属性TextBlock
来显示椭圆
<TextBlock
Name="sampleTextBlock"
TextTrimming="WordEllipsis"
TextWrapping="NoWrap"/>
<Window.Resources>
<ResourceDictionary Source="/PresentationFramework.Aero, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL;component/themes/aero.normalcolor.xaml" />
</Window.Resources>
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: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>
在禁用的控件上显示工具提示
如果控件处于禁用状态,Wpf 允许在控件上显示工具提示。
例如
<Button Content="Disabled Button" ToolTipService.ShowOnDisabled="True" IsEnabled="False" ToolTip="This is a disabled button"/>
不是真正的隐藏功能,但使用 WPF/XAML 你会得到Bea Stollnitz和Josh Smith。WPF/XAML 编程的女王和王者。
标记扩展和附加属性是我最喜欢的功能,它们使您能够以非常优雅的方式扩展 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的来源(顺便说一句,它使用了GridViewColumnHeader.Click
Ortus 提到的事件)
您可以使用加号 ( +
) 引用 XAML 中的嵌套类型。例如,如果我们有这个类:
public class SomeClass
{
public enum SomeEnum
{
SomeValue
};
}
我们可以SomeValue
使用以下语法在 XAML 中引用:
{x:Static local:SomeClass+SomeEnum.SomeValue}
此语法未在 MSDN 上记录,并且不受官方支持。有人在 MSDN 论坛上询问过,显然它破坏了 VS2010 的 WPF Designer。它已在 Microsoft Connect 上进行了报道。
网格大小共享(这是一个很好的例子)。长话短说,您可以让网格列和行共享大小,甚至跨不同的网格。这对于所有使用 DataGrids 而无需就地编辑数据的人来说将是无价的。
优先绑定。允许您以“先到先显示”的顺序使用异步绑定:
<TextBlock.Text>
<PriorityBinding FallbackValue="defaultvalue">
<Binding Path="SlowestDP" IsAsync="True"/>
<Binding Path="SlowerDP" IsAsync="True"/>
<Binding Path="FastDP" />
</PriorityBinding>
</TextBlock.Text>
通过 x:FactoryMethod 使用静态工厂方法
当您的类型没有公共构造函数但有静态工厂方法时,您必须在 XAML 2006 的代码中创建该类型。使用 XAML 2009,您可以使用 x:FactoryMethodx:Arguments 属性来传递参数值。
<!-- XAML 2006 -->
Guid id = Guid.NewGuid();
<!-- XAML 2009 -->
<Guid x:FactoryMethod="Guid.NewGuid" />
还有一点不是很清楚,就是我们习惯的一些属性的内容只包含文本。如果 GUI 元素的属性是 Object 类型,则很可能您可以添加一个包含一组控件的面板,而不仅仅是设置文本。
MenuItem 就是一个例子,其中的Header
属性(通常只包含文本)可以包含一组封装在面板控件中的 gui 元素(或者如果您只需要一个 gui 元素,则只需一个 gui 元素)。
还要注意Icon
MenuItem 上的属性。这通常包含一个 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>
XAML 转换器
以下列表显示了 WPF 社区开发的用于将不同格式转换为 XAML 或反之亦然的转换器。
<Border Background="{DynamicResource {x:Static SystemColors.InactiveBorderBrushKey}}"/>
内置类型
如果您想将简单类型的对象(如 string 或 double)添加到资源字典中,则需要将所需的 clr-namespaces 映射到 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/>
使用 {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" />
支持任意字典键
在 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>
通过代码设置 ValidationError
BindingExpression 中的 ValidatioRule 仅在绑定的目标端发生更改时触发。如果要通过代码设置验证错误,可以使用以下代码段。
设置验证错误
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));
将 UIElement(s) 填充到 TextBlock 中的能力
我不知道这是多么有用(虽然它有资格被隐藏)......但当我第一次遇到它时它确实让我措手不及:
<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 呈现如下:
调试动画
常见错误
如果您收到以下错误:Cannot animate '(0).(1)' on an immutable object instance。可能是您遇到了以下限制之一:
没有 INotifyPropertyChanged 或 DependencyProperties 的绑定
正如这里所讨论的,您可以在没有 INotifyPropertyChanged 的情况下绑定一个普通的 CLR 对象属性,并且它可以正常工作。
这是我指的论坛帖子。
引用:
[...] 如果源对象是普通 CLR 对象并且不实现 INotifyPropertyChanged 接口,WPF 的数据绑定引擎会将数据绑定到包装源属性的 PropertyDescriptor 实例。并且数据绑定引擎将尝试通过 PropertyDescriptor.AddValueChanged() 方法订阅属性更改事件。而当目标数据绑定元素改变属性值时,数据绑定引擎会调用 PropertyDescriptor.SetValue() 方法将改变后的值传回源属性,同时会引发 ValueChanged 事件通知其他订阅者(在这种情况下,其他订阅者将是 ListBox 中的 TextBlock。
如果您正在实施 INotifyPropertyChanged,您将完全负责在需要将数据绑定到 UI 的属性的每个设置器中实施更改通知。否则,更改将不会像您期望的那样同步。[...]
这是关于该主题的另一篇精彩而详细的文章。
请注意,这仅在使用 binding 时有效。如果您从代码更新值,则不会通知更改。[...]
实现 INotifyPropertyChanged 可能是相当乏味的开发工作。但是,您需要根据 WPF 应用程序的运行时占用空间(内存和 CPU)权衡该工作。自己实现 INPC 将节省运行时 CPU 和内存。