2010-11-09 4 views
14

J'ai le code-behind ci-dessous:Reliure ObservableCollection à ListBox WPF

public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     ObservableCollection<int> sampleData = new ObservableCollection<int>(); 
     public ObservableCollection<int> SampleData 
     { 
      get 
      { 
       if (sampleData.Count <= 0) 
       { 
        sampleData.Add(1); 
        sampleData.Add(2); 
        sampleData.Add(3); 
        sampleData.Add(4); 
       } 
       return sampleData; 
      } 
     } 
    } 

Mon XAML est:

<Window x:Class="Sandbox.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"> 
    <Grid> 
     <ListBox ItemsSource="{Binding Path=SampleData}"/> 
    </Grid> 
</Window> 

La liste ne présente pas les valeurs de la collection (ou quoi que ce soit). Quelqu'un peut-il préciser quelle est mon erreur?

Ai-je besoin de définir explicitement le DataContext? Je pensais que si aucun n'est défini, le contrôle utilisera simplement lui-même en tant que DataContext.

+0

Cela fonctionne-t-il si vous définissez le DataContext explicitement? – user200783

Répondre

20

Oui, vous devez définir le DataContext en quelque sorte. Il n'a pas de DataContext, car la fenêtre n'a pas de DataContext à moins qu'elle ne soit définie. Le ListBox obtiendra le DataContext si vous faites cela dans le constructeur.

public MainWindow() 
{ 
    InitializeComponent(); 
    this.DataContext = this; 
} 

Sinon, vous pouvez utiliser RelativeSource, etc. ElementName dans la reliure mais je suppose que vous saviez que =)

4

Je passe habituellement un viewmodel dans le constructeur et définir le datacontext au viewmodel transmis. Ensuite, votre ObservableCollection peut être déplacée hors de la vue et placée dans le viewmodel. Cela sépare votre vue de votre logique et vous permet également de tester le code viewmodel.

public MainWindow(SomeViewModel viewModel) 
{ 
    DataContext = viewModel; 

    InitializeComponent(); 
} 
2

Essayez d'utiliser le Patern MVVM donc dans la vue, vous pouvez définir la zone de liste comme ceci:

<ListBox ItemsSource="{Binding Path=Log, UpdateSourceTrigger=PropertyChanged}"/> 

Ensuite, la vue peut être sans code derrière lié à la source de liaison. Dans le ViewModel vous ajoutez liés quelque chose comme ceci:

public class ViewModel : ViewModelBase 
{ 
    //... 
    private ObservableCollection<string> p_Log; 

    /// <summary> 
    /// A log of a starting process 
    /// </summary> 
    public ObservableCollection<string> Log 
    { 
     get { return p_Log; } 

     set 
     { 
      base.RaisePropertyChangingEvent("Log"); 
      p_Log.Add(value.ToString()); 
      base.RaisePropertyChangedEvent("Log"); 
     } 
    } 
    //.... 
    /// <summary> 
    /// Initializes this view model. 
    /// </summary> 
    /// <param name="mainWindowViewModel">The view model for this application's main window.</param> 
    private void Initialize(MainWindowViewModel mainWindowViewModel) 
    { 
     //... 
     p_Log = new ObservableCollection<string>(); 
    } 

et les événements définis dans ViewModelBase gardera la liaison dans la vue mise à jour, sans avoir besoin d'un code derrière la vue chaque fois qu'une nouvelle chaîne est ajoutée à la collection observable p_log.