tutorial - ¿Funciones ocultas de WPF y XAML?
wpf xaml tutorial (25)
Propiedades avanzadas de "título"
Otra cosa que no está muy clara es el contenido de algunas propiedades que estamos acostumbrados a contener solo texto. Si la propiedad de un elemento GUI es de tipo Object, es muy probable que pueda, en lugar de simplemente configurar el texto, agregar un panel de su necesidad que incluya un conjunto de controles.
Un ejemplo de esto es MenuItem, donde la propiedad Header
(que normalmente solo contiene texto) puede contener un conjunto de elementos gui envueltos en un control de panel (o solo un elemento gui si solo necesita uno).
También tenga en cuenta la propiedad Icon
en el MenuItem. Esto normalmente contiene un elemento Imagen, ¡pero esto también puede contener cualquier cosa!
<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>
Aquí hay una gran cantidad de características ocultas discutidas para una variedad de idiomas. Ahora tengo curiosidad acerca de algunas características ocultas de XAML y WPF.
Uno que he encontrado es el evento de clic de encabezado de un ListView
<ListView x:Name=''lv''
Height="150"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
La propiedad GridViewColumnHeader.Click no aparece en la lista.
Algunas de las características relevantes hasta el momento:
Ver también:
Uso de colores del sistema
<Border Background="{DynamicResource {x:Static SystemColors.InactiveBorderBrushKey}}"/>
3.5sp1 introdujo StringFormat en expresiones vinculantes, por ejemplo
<TextBox Text="{Binding Date, StringFormat=''{}{0:MM/dd/yyyy}''}" />
3.5sp1 introdujo TargetNullValue a los enlaces. Esto establecerá la propiedad vinculada en Nulo si se ingresa el valor y si su propiedad es nula, mostrará este valor.
<TextBox Text="{Binding Total, TargetNullValue=$0.00}" />
Algunas veces obtienes una cuerda que es demasiado larga para mostrarla en la etiqueta. En este caso, podemos hacer uso de la propiedad TextTrimming
de TextBlock
para mostrar elipses
<TextBlock
Name="sampleTextBlock"
TextTrimming="WordEllipsis"
TextWrapping="NoWrap"/>
Las extensiones de marcado y las propiedades adjuntas son mis características favoritas, le permiten extender el "vocabulario" de XAML de una manera muy elegante.
Extensiones de marcado
<!-- 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}"/>
Propiedades adjuntas
<!-- 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">
...
Fuente para GridViewSort (por cierto, utiliza el evento GridViewColumnHeader.Click
mencionado por Ortus)
No es realmente una función oculta, pero con WPF / XAML obtienes a Bea Stollnitz y Josh Smith . Reina y Rey de la programación WPF / XAML.
Puede hacer referencia a tipos anidados en XAML usando el signo más ( +
). Por ejemplo, si tuviéramos esta clase:
public class SomeClass
{
public enum SomeEnum
{
SomeValue
};
}
Podríamos referirnos a SomeValue
en XAML usando la siguiente sintaxis:
{x:Static local:SomeClass+SomeEnum.SomeValue}
Esta sintaxis no está documentada en MSDN , y no es oficialmente compatible. Alguien preguntó al respecto en los foros de MSDN, y aparentemente rompe el Diseñador WPF de VS2010. Se ha informado sobre Microsoft Connect.
Tamaño de la red compartida (he here''s un buen ejemplo). En pocas palabras, puede tener columnas de cuadrícula y filas de tamaños compartidos, incluso a través de diferentes cuadrículas. Esto será invaluable para todas las personas que usan DataGrids sin la necesidad de editar los datos en su lugar.
También existe el truco PresentationTraceSources.TraceLevel para depurar lo que está sucediendo con los enlaces en cualquier escenario particular. Todo lo que tiene que hacer es hacer referencia al espacio de nombres de System.Diagnostics en el ensamblado de WindowsBase
xmlns:sd="clr-namespace:System.Diagnostics;assembly=WindowsBase"
y luego agregue siguiente a la expresión de enlace:
<TextBlock Text="{Binding Message, sd:PresentationTraceSources.TraceLevel=High}" />
Log será así:
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
Multibinding (combinado con StringFormat):
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}, {1}">
<Binding Path="LastName" />
<Binding Path="FirstName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Animaciones de depuración
Errores comunes
Si obtiene el siguiente error: No se puede animar ''(0). (1)'' en una instancia de objeto inmutable. podría ser que se encuentre con una de las siguientes limitaciones:
- Está animando una propiedad de dependencia sin establecer un valor local
- Usted está animando una propiedad de dependencia cuyo valor actual se define en otro ensamblaje que no está fusionado en el diccionario de recursos.
- Estás animando un valor que está actualmente vinculado a datos
Conversores XAML
La siguiente lista muestra convertidores desarrollados por la comunidad WPF para convertir diferentes formatos a XAML o viceversa.
Complemento de exportación Adobe Illustrator XAML
Adobe Photoshop a XAML Converter
Establecer un ValidationError por código
Una ValidatioRule en una BindingExpression solo se activa cuando cambia el lado de destino de la vinculación. Si desea establecer un error de validación por código, puede usar el siguiente fragmento.
Establecer el error de validación
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);
Borrar el error de validación
Validation.ClearInvalid(textBox.GetBindingExpression(TextBox.TextProperty));
Genéricos en XAML con x: TypeArguments
Si desea utilizar un ObservableCollection en XAML, necesita crear un tipo que se deriva de ObservableCollection porque no puede declararlo en XAML. Con XAML 2009 puede usar el atributo x: TypeArguments para definir el tipo de un tipo genérico.
<!-- 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 />
Mostrar información sobre herramientas en un control deshabilitado
Wpf permite mostrar información sobre herramientas en un control, si está en estado desactivado.
Por ejemplo
<Button Content="Disabled Button" ToolTipService.ShowOnDisabled="True" IsEnabled="False" ToolTip="This is a disabled button"/>
Referencias de objetos sencillos con {x: referencia}
Si desea crear una referencia de objeto hoy, debe realizar un enlace de datos y declarar el origen con un ElementName. En XAML 2009 puede usar la nueva extensión de marcado {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" />
Soporte para claves de diccionario arbitrario
En XAML 2006, todas las x explícitas: el valor clave se trataron como cadenas. En XAML 2009 puede definir cualquier tipo de clave que desee escribiendo la clave en 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>
Tipos incorporados
Si desea agregar objetos de tipos simples como cadena o doble a un diccionario de recursos, debe mapear los espacios de nombres clr necesarios en espacios de nombres XML. En XAML 2009 tenemos muchos tipos simples que se incluyen en el lenguaje XAML.
<!-- XAML 2006 -->
<sys:String xmlns:sys="clr-namespace:System;assembly=mscorlib >Test</sys:String>
<!-- XAML 2009 -->
<x:String>Test</x:String>
Los siguientes tipos están incluidos en el lenguaje 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/>
Uso de constructores no predeterminados con x: argumentos
En XAML 2006, los objetos deben tener un constructor predeterminado público para usarlos. En XAML 2009 puede pasar argumentos constructor utilizando la sintaxis x: Arguments.
<!-- XAML 2006 -->
<DateTime>00:00:00.0000100</DateTime>
<!-- XAML 2009 -->
<DateTime>
<x:Arguments>
<x:Int64>100</x:Int64>
</x:Arguments>
</DateTime>
Uso de métodos estáticos de fábrica con x: FactoryMethod
Cuando tiene un tipo que no tiene un constructor público sino un método de fábrica estático, debe crear ese tipo de código en XAML 2006. Con XAML 2009, puede usar el atributo x: FactoryMethodx: Arguments para pasar los valores del argumento.
<!-- XAML 2006 -->
Guid id = Guid.NewGuid();
<!-- XAML 2009 -->
<Guid x:FactoryMethod="Guid.NewGuid" />
PriorityBinding . Le permite usar enlaces asyn en un orden de "primero en llegar primero":
<TextBlock.Text>
<PriorityBinding FallbackValue="defaultvalue">
<Binding Path="SlowestDP" IsAsync="True"/>
<Binding Path="SlowerDP" IsAsync="True"/>
<Binding Path="FastDP" />
</PriorityBinding>
</TextBlock.Text>
Enlace sin INotifyPropertyChanged o DependencyProperties
Como se discutió here , puede vincular una propiedad de objeto CLR simple sin INotifyPropertyChanged, y simplemente funcionará .
Aquí está el Forumpost al que me refiero.
Citar:
[...] El motor de enlace de datos de WPF vinculará los datos a la instancia de PropertyDescriptor que envuelve la propiedad de origen si el objeto de origen es un objeto CLR simple y no implementa la interfaz INotifyPropertyChanged. Y el motor de enlace de datos intentará suscribirse al evento de propiedad modificada a través del método PropertyDescriptor.AddValueChanged (). Y cuando el elemento enlazado de datos de destino cambia los valores de las propiedades, el motor de enlace de datos llamará al método PropertyDescriptor.SetValue () para transferir el valor cambiado a la propiedad de origen, y simultáneamente generará un evento ValueChanged para notificar a otros suscriptores (en este caso, los otros suscriptores serán los TextBlocks dentro del ListBox.
Y si está implementando INotifyPropertyChanged, usted es totalmente responsable de implementar la notificación de cambio en cada setter de las propiedades que deben estar vinculadas a la interfaz de usuario. De lo contrario, el cambio no se sincronizará como era de esperar. [...]
Aquí hay otro artículo excelente y detallado sobre el tema.
Tenga en cuenta que esto solo funciona cuando se usa el enlace . Si actualiza los valores del código , no se notificará el cambio. [...]
La implementación de INotifyPropertyChanged puede ser un poco tedioso de trabajo de desarrollo. Sin embargo, deberá ponderar ese trabajo con el espacio de tiempo de ejecución (memoria y CPU) de su aplicación WPF. La implementación de INPC usted mismo guardará la CPU y la memoria del tiempo de ejecución .
La capacidad de rellenar el / los UIElement (s) en un TextBlock
No sé qué tan útil (califica como oculto) es ... pero seguro me pilló desprevenido cuando me topé por primera vez con él :
<Grid x:Name="LayoutRoot">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Rectangle Fill="AliceBlue" Width="25" Height="25"/>
</Grid>
</TextBlock>
</Grid>
Podría argumentar que la siguiente xaml podría ser útil (es decir, poner un gráfico al final de un texto):
<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>
El xaml anterior se representa como el siguiente:
Agregar el efecto Aero a la ventana
<Window.Resources>
<ResourceDictionary Source="/PresentationFramework.Aero, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL;component/themes/aero.normalcolor.xaml" />
</Window.Resources>