2013-04-10 10 views
10

Ich habe die folgende Windows RT-App. Ich binde eine Liste von Strings an ein ItemsControl von TextBlocks. Dadurch werden die leeren Zeichenfolgen als "System.Collections.Generic.List'1 [System.String]" anstelle nur einer leeren Zeichenfolge angezeigt. Ich möchte, dass es eine leere Zeichenfolge anstelle des Typs des DataContext anzeigt.TextBlock-Bindung zeigt den Klassennamen anstelle der leeren Zeichenfolge an

Code hinter:

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> 

Ausgang:

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

Ich habe das gleiche Beispiel mit traditionellen wpf und es zeigt die leeren Zeichenfolge korrekt.

Bearbeiten Dies gibt das gleiche aus.

Code hinter:

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> 
+0

Ich habe es nicht getestet, aber es scheint wie ein Fehler in der Plattform, Aber wie auch immer - das scheint nicht der typische Mainstream-Weg zu sein, Bindungen zu verwenden. Personen legen ItemsSource entweder direkt auf eine Auflistung fest oder verwenden einen Ansichtsmodelltyp, der eine Auflistungseigenschaft freigibt, die Sie dann an ItemsSource Ihres ItemsControl binden würden. Ich habe noch nie jemanden gesehen, der einen DataContext zu einer Sammlung gesetzt hat oder einen guten Grund dafür gesehen hat. –

+0

Dies ist nur ein Beispiel. Die Anwendung, die ich erstelle, weist den DataContext einem ViewModel zu, das eine Eigenschaft vom Typ List hat. –

Antwort

5

Sie können tatsächlich sehen, dass es ein Fehler (oder seltsame intentionale Funktion) ist, indem Sie einen Konverter zum TextBlockBinding hinzufügen.

eine statische Ressource hinzufügen:

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

Anschließend wird die Bindung ändern Sie den Konverter zu verweisen:

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

Fügen Sie diese Klasse:

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(); 
    } 
} 

Wenn Sie einen Haltepunkt setzen auf die return Anweisung, Sie werden sehen, dass der erste Wert, der tatsächlich übergeben wird, die gesamte Liste ist. Ja, unerwartet. Wenn Sie diesen Konverter jedoch wie beschrieben verwenden, behandelt er diese Kuriosität und gibt nur eine logischere leere Zeichenfolge zurück.

Oder Sie etwas mehr interessante und erstellen Sie eine einfache Wrapper-Klasse tun können:

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; 
    } 
} 

Mit dieser Klasse können Sie nur die Bindung wie erwartet verwenden:

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

jedoch Sie müssten in der Deklaration der Liste einen anderen Klassentyp verwenden:

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

Mit der impliziten Umwandlung funktioniert es "einfach", da es die String in eine StringContext konvertiert. Ja, es würde den Overhead zum Erstellen einer unnötigen Klasse hinzufügen, aber es funktioniert. :) Ich würde die Option Konverter bevorzugen.

+0

Ich habe auch einen Konverter erstellt, um zu sehen, was vor sich geht. Ich denke, es ist ein Fehler. Ich werde den Konverter benutzen um zu arbeiten. Vielen Dank! –

+0

Lief auch in diesen Fehler. Ich habe mehr mit Code-Behind gearbeitet, also denke ich, dass ich ein bisschen mehr Informationen habe. Es scheint, dass die Bindungseigenschaft 'TargetNullValue' unterbrochen ist. Wenn Sie eine leere Zeichenfolge eingeben, erhalten Sie das oben beschriebene Verhalten. Wenn Sie es mit einem einzelnen Leerzeichen füllen, füllt es die Nullwerte mit dem einzelnen Leerzeichen. Sie machen wahrscheinlich 'IsNullOrEmpty' hinter den Kulissen, wenn sie nur mit null vergleichen wollten. –

1

Ich kann wirklich nicht erklären, warum, aber es funktioniert wie erwartet, wenn Sie direkt auf die ItemsSource Eigenschaft:

<ItemsControl x:Name="itemsControl"> 
    ... 
</ItemsControl> 

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

Ich auch dies versucht:

<ItemsControl ItemsSource="{Binding Items}"> 
    ... 
</ItemsControl> 

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

public IEnumerable Items { get; set; } 

aber es ergibt sich die Anzeige

TextBlockBindingTest.MainPage

nicht leeren String

Offenbar, wenn das Element Bindung auswertet zu null oder leer, fällt es auf den geerbten DataContext zurück. Ich denke, das ist ein Fehler in WinRT.


Alternativ können Sie auch die Name Eigenschaft der Mainpage-Klasse festgelegt und eine Bindung wie folgt schreiben:

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

und nicht gesetzt Datacontext:

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

oder versuchen eingestellt Bindungscode hinten:

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

Das funktionierte für mich.

+0

Das funktioniert, aber nicht, weil es Code-Behind ist. Es funktioniert, weil Sie keinen DataContext, sondern stattdessen die Bindungsquelle festlegen. – Clemens

0

Eigentlich stolperte ich über eine einfachere Lösung. Dies ist zweifellos ein Fehler. Derselbe Code in WPF gibt die erwarteten Ergebnisse. Die Quelle des Fehlers ist die TargetNullValue-Eigenschaft, die leere Zeichenfolgen nicht richtig interpretiert. Um den Fehler zu erhalten, können Sie entweder der IValueConverter oben vorgeschlagen (Converter-Lösungen haben Leistungsprobleme aus meiner Erfahrung) oder -nutzung:

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