visual tutorial studio app xaml binding windows-runtime microsoft-metro winrt-xaml

xaml - tutorial - El enlace TextBlock muestra el nombre de clase en lugar de una cadena vacía



xaml visual studio 2017 (4)

De hecho, puede ver que se trata de un error (o una característica intencional extraña) al agregar un convertidor a la Binding TextBlock .

Agregue un recurso estático:

<Page.Resources> <local:NoNullsConverter x:Key="fixNulls"></local:NoNullsConverter> </Page.Resources>

A continuación, cambie la vinculación para hacer referencia al convertidor:

<TextBlock Text="{Binding Converter={StaticResource fixNulls}}" FontSize="25"/>

Agrega esta clase:

public class NoNullsConverter : IValueConverter { // This converts the value object to the string to display. public object Convert(object value, Type targetType, object parameter, string language) { return value is string ? value : ""; } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }

Si coloca un punto de corte en la declaración de return , verá que el primer valor que se pasa en realidad es la lista completa. Sí, inesperado. Sin embargo, si usa este convertidor como está escrito, maneja esa rareza y simplemente devuelve una cadena vacía más lógica.

O bien, puede hacer algo más interesante y crear una clase contenedora simple:

public class StringContext { public string Value { get; set; } public static implicit operator StringContext(string value) { return new StringContext() { Value = value }; } public override string ToString() { return Value; } }

Con esta clase, puede usar el Enlace como se esperaba:

<TextBlock Text="{Binding}" FontSize="25"/>

Sin embargo, necesitaría usar un tipo de clase diferente en la declaración de la Lista:

DataContext = new List<StringContext>() { "", "not empty string" };

Usando el modelo implícito, "simplemente funciona", ya que convierte String a StringContext . Sí, agregaría la sobrecarga de crear una clase innecesaria, pero funciona. :) Preferiría la opción Convertidor.

Tengo la siguiente aplicación de Windows RT. Ato una Lista de cadenas a un ItemsControl de TextBlocks. Esto mostrará las cadenas vacías como "System.Collections.Generic.List''1 [System.String]" en lugar de solo una cadena vacía. Me gustaría que muestre una cadena vacía en lugar del tipo de DataContext.

código detrás:

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); DataContext = new List<string>() { "", "not empty string" }; } }

xaml:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <ItemsControl ItemsSource="{Binding}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" FontSize="25"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid>

salida:

System.Collections.Generic.List''1[System.String] non empty string

Hice el mismo ejemplo con wpf tradicional y muestra las cadenas vacías correctamente.

Editar Esto produce lo mismo.

código detrás:

public class Model { private readonly List<string> items = new List<string>() { "", "non empty string" }; public List<string> Items { get { return items; } } } public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); DataContext = new Model(); } }

xaml:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <ItemsControl ItemsSource="{Binding Path=Items}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" FontSize="25"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid>


Realmente no puedo explicar por qué, pero funciona como se esperaba cuando estableces directamente la propiedad ItemsSource :

<ItemsControl x:Name="itemsControl"> ... </ItemsControl> public MainPage() { this.InitializeComponent(); itemsControl.ItemsSource = new List<string>() { "", "not empty string" }; }

También intenté esto:

<ItemsControl ItemsSource="{Binding Items}"> ... </ItemsControl> public MainPage() { this.InitializeComponent(); Items = new List<string>() { "", "not empty string" }; DataContext = this; } public IEnumerable Items { get; set; }

pero resulta en mostrar

TextBlockBindingTest.MainPage

cadena no vacía

Aparentemente, cuando el enlace del elemento se evalúa como nulo o vacío , regresa al DataContext heredado. Supongo que esto es un error en WinRT.

Alternativamente, también puede establecer la propiedad Name de la clase MainPage y escribir un enlace como este:

<Page ... x:Name="mainPage"> ... <ItemsControl ItemsSource="{Binding Items, ElementName=mainPage}"> ... </ItemsControl>

y no establece el DataContext:

public MainPage() { this.InitializeComponent(); Items = new List<string>() { "", "not empty string" }; }


o intente configurar el código de enlace detrás:

//list is ItemsControl var bin = new Binding(); var mylist = new List<string>(){"","not empty string"}; bin.Source = mylist; list.SetBinding(ItemsControl.ItemsSourceProperty,bin);

Esto funcionó para mí.


En realidad, me encontré con una solución más simple. Esto es, sin duda, un error. El mismo código en WPF da los resultados esperados. El origen del error es la propiedad TargetNullValue, que no interpreta las cadenas vacías correctamente. Para evitar el error, puede utilizar el IValueConverter sugerido anteriormente (las soluciones de conversión tienen problemas de rendimiento según mi experiencia) o usar:

<TextBlock Text="{Binding TargetNullValue='' ''}" FontSize="25"/>