2013-03-04 5 views
12

Ich versuche Data Binding zu verwenden, um eine ObservableCollection an die ItemsSource eines DataGrid zu binden, wenn ich etwas über WPF und andere Dinge erfahre. Im Code-Behind kann ich den DataContext mit this.DataContext = this; oder bloopDataGrid.DataContext = this; setzen. Das ist gut und gut.Warum funktioniert die Bindung des MainWindow-Datenkontexts in XAML nicht so wie die Bindung im Codebehind mit this.datacontext = this?

Ich dachte, ich so etwas wie

<Window.DataContext> 
    <local:MainWindow/> 
</Window.DataContext> 

in meinem Hauptfenster versuchen könnte, aber dies führt zu einem Stack-Überlauf Ausnahme wie in this question erläutert. Gut, das macht Sinn.

Nach der Lektüre this und anderen Fragen/Antworten, die sagen DataContext="{Binding RelativeSource={RelativeSource Self}}" im Fenster des XAML-Code, um zu versuchen, dachte ich, ich könnte tatsächlich diesen tun. Anscheinend kann ich nicht. Oder zumindest, die IDE lässt mich und es ist syntaktisch korrekt, aber tut nicht, was ich will (dh genau was this.DataContext = this; tut).

Dann las ich this über "{Binding ElementName=, Path=}" mit und versucht, es wie so zu verwenden:

<DataGrid 
    Name="bloopDataGrid" 
    Grid.Row="1" 
    ItemsSource="{Binding ElementName=testWin, Path=OutputCollection}"> 
</DataGrid> 

Welche auch nicht funktioniert. Vielleicht nicht aus dem gleichen Grund, aber ich kann das Problem damit nicht lösen.

Seltsamerweise kann ich das in Rachel Lim's blog post gezeigte Beispiel für eine erneute Bindung nicht replizieren.

XAML:

<Window 
    x:Class="DataBinding.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" 
    Height="350" 
    Width="525" 
    x:Name="testWin"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 

     <Label Grid.Row="0" Content="{Binding text}"> 
     </Label> 

     <DataGrid 
      Name="bloopDataGrid" 
      Grid.Row="1" 
      ItemsSource="{Binding Path=OutputCollection}"> 
     </DataGrid> 
    </Grid> 
</Window> 

C#:

using System; 
using System.Collections.ObjectModel; //For ObservableCollection<T> 
using System.Windows; 

namespace DataBinding 
{ 
    public partial class MainWindow : Window 
    { 
     public String text { get; set; } 
     public ObservableCollection<testStruct> OutputCollection { get; set; } 

     public struct testStruct 
     { 
      public testStruct(String x, String y) : this() 
      { 
       Col1 = x; 
       Col2 = y; 
      } 
      public String Col1 { get; set; } 
      public String Col2 { get; set; } 
     } 

     public MainWindow() 
     { 
      InitializeComponent(); 

      testA t1 = new testA(); 
      this.DataContext = this; 
      //this.DataContext = t1; 
      //bloopDataGrid.DataContext = this; 
      text = "bound \"this\""; 
      t1.text = "bound a class"; 

      OutputCollection = new ObservableCollection<testStruct>(); 
      OutputCollection.Add(new testStruct("1", "2")); 
      OutputCollection.Add(new testStruct("3", "4")); 
     } 

     public class testA 
     { 
      public String text { get; set; } 
     } 

    } 
} 

Der obige Code ist das, was ich verwende dies zu testen, und zur Zeit der Code-Behind-Version verwendet, die richtig gibt mir

In codebehind

Was mache ich falsch, was mich daran hindert, die gleichen Ergebnisse wie das obige Bild zu erhalten, aber mit XAML für die DataContext-Behandlung? Verbinde ich die Punkte nicht richtig? ... fehlen mir einige Punkte?

Antwort

25
<Window.DataContext> 
    <local:MainWindow/> 
</Window.DataContext> 

ist nicht dasselbe wie

this.DataContext = this; 

Die erste ist eine neue Instanz der MainWindow Klasse zu schaffen, und dass an die DataContext Eigenschaft des Window Zuweisen, während der zweite die gleiche Zuweisen Instanz der Window zu seiner DataContext Eigenschaft.

Damit in XAML zu erreichen, müssen Sie ein RelativeSource Bindung verwenden:

<Window DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
</Window> 

Edit: zwischen der Definition hinter dem DataContext in XAML und in Code

Der Unterschied im Verhalten ist verursacht durch die Tatsache, dass XAML tatsächlich geparst wird, wenn der Konstruktor die Ausführung beendet, weil darauf wartet, dass der Benutzercode (im Konstruktor des Fensters) beendet wird, bevor seine ausstehenden Operationen ausgeführt werden.

Das bewirkt, dass die tatsächlichen Eigenschaftswerte in diesen verschiedenen Momenten unterschiedlich sind, und da es keine INotifyPropertyChanged gibt, kann WPF die Benutzeroberfläche nicht aktualisieren, um die neuen Werte wiederzugeben.

could Sie implementieren INotifyPropertyChanged im Window selbst, aber ich schlage vor, ein Ansichtsmodell dafür zu schaffen, wie Ich mag nicht die Tatsache INotifyPropertyChanged des Mischens (was eher ein Ansichtsmodell Konzept ist) mit DependencyObject abgeleiteten Klassen (UI-Elemente).

+0

Ich erwähnte, dass dies für mich nicht funktioniert hat, und dass ich herausgefunden habe, was das Problem mit MainWindow ist, indem ich die andere Frage darüber ansehe. – Hydronium

+0

Ihr Problem besteht darin, dass Sie Ihre Datenelemente innerhalb der 'MainWindow'-Klasse selbst zusammensetzen. Sie sollten ein ViewModel erstellen und 'INotifyPropertyChanged' implementieren. –

+0

Ich bin mir nicht sicher, ob ich das verstehe. Kann ich das MVVM-Muster für alle meine Programme in WPF einhalten? Wie wird das Problem, das ich habe, durch eine neue Klasse behoben? Ich würde es lieber reparieren oder herausfinden, warum es nicht funktioniert, nicht strikt vermeiden, nur weil ich es nicht verstehe. – Hydronium

Verwandte Themen