2010-05-21 8 views
0

Je suis en train de lier un tableau 2D de boutons disposés en stackpanels une 2D ObservableCollection ...Confusion au sujet WPF contraignant

Pourtant, je crains que je ne comprends pas quelque chose de très élémentaire sur la liaison.

Mon XAML:

<Window.Resources> 
    <DataTemplate x:Key="ItemsAsButtons"> 
     <Button Content="{Binding}" Height="100" Width="100"/> 
    </DataTemplate> 
    <DataTemplate x:Key="PanelOfPanels"> 
     <ItemsControl ItemsSource="{Binding Path=DayNumbers}" ItemTemplate=" {DynamicResource ItemsAsButtons}"> 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
        <StackPanel Orientation="Horizontal"/> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
     </ItemsControl> 
    </DataTemplate> 
    </Window.Resources> 

... 
     <ItemsControl x:Name="DaysPanel" Grid.ColumnSpan="7" Grid.Row="2" 
         ItemTemplate="{DynamicResource PanelOfPanels}"/> 

Mon code C#: Le backend:

/// <summary> 
/// Window BE for Calendar.xaml 
/// </summary> 
public partial class Calendar : Window 
{ 

    private CalendarViewModel _vm; 
    public Calendar() 
    { 
     InitializeComponent(); 
     _vm = new CalendarViewModel(); 
     this.DataContext = _vm; 
    } 
} 

ViewModel:

class CalendarViewModel 
{ 
    CalendarMonth _displayedMonth; 
    EventCalendar _calendar; 

    public CalendarViewModel() 
    { 
     _displayedMonth = new CalendarMonth(); 
    } 

    public ObservableCollection<ObservableCollection<int>> DayNumbers 
    { 
     get 
     { 
      return _displayedMonth.DayNumbers; 
     } 
    } 
} 

Je suis en train de remplir les boutons avec des valeurs de CalendarViewModel.DayNumbers - pourtant les boutons n'apparaissent pas. Je fais clairement quelque chose de mal avec ma liaison.

Répondre

2
  1. Comme Igor dit, vous devez spécifier ItemsSource={Binding DayNumbers} dans le plus extérieur ItemsControl, sinon, il se lie au DataContext, qui est CalendarViewModel et ce n'est pas IEnumerable. Une fois que vous faites cela, il s'appliquera <DataTemplate x:Key="PanelOfPanels"> pour chaque article à DayNumbers. Notez que le DataContext du DataTemplate dans chaque élément dans DayNumbers, qui est de type ObservableCollection<int>. Ici, vous ne pouvez pas spécifier ItemsSource="{Binding Path=DayNumbers}" car DayNumbers n'est pas une propriété valide dans ObservableCollection<int>. Au lieu de cela, puisque ObservableCollection<int> est déjà un IEnumerable, il convient de ne pas spécifier ItemsSource car il sera par défaut lié à DataContext. Enfin, il va à votre <DataTemplate x:Key="ItemsAsButtons"> le plus à l'intérieur, et vous pouvez mettre le bouton là comme vous l'avez fait.

Espérons que cela clarifie un peu. Désolé, je n'ai pas l'environnement pour le tester et vous donner la solution.

Le débogage des liaisons WPF n'est pas simple. Une astuce est que vous pouvez utiliser le convertisseur factice et définir la méthode point d'arrêt dans Convert pour voir ce qu'il se fixe.

public class DebugConverter1 : IValueConverter 
    { 
    #region IValueConverter Members 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value; 
    } 

    #endregion 
    } 

{Binding Converter={StaticResource debugConverter1}} 
+0

Maintenant, je comprends - je devais spécifier une liaison simple dans la liste de niveau supérieur, je peux voir Igor disait maintenant. – Vladislav

3

Remplacez tous vos DynamicResource par StaticResource. Cela ne devrait pas l'empêcher de fonctionner, mais pourrait être inefficace à l'exécution. Jetez un oeil this page pour l'aperçu des ressources WPF.

De même, votre ItemsControl n'est pas lié à DayNumbers. Ajouter une reliure comme ceci:

<ItemsControl x:Name="DaysPanel" Grid.ColumnSpan="7" Grid.Row="2" 
        ItemTemplate="{StaticResource PanelOfPanels}" 
        ItemsSource={Binding DayNumbers}/> 

Lorsque vous définissez la DataContext sur la fenêtre du calendrier vous définissez quel objet sera la source de liaison par défaut de la fenêtre entière. Vous n'avez pas spécifié la propriété de votre ViewModel liée au ItemsControl. C'est ce que fait le code ci-dessus.

EDIT Parce que vous remplacez le modèle d'élément pour la ItemsControl et de fournir un conteneur de collecte là, vous devez fournir les ItemsSource pour elle aussi. La syntaxe {Binding} signifie simplement lier à chaque membre ou l'énumération, dans ce cas ObservableCollection<int>.

Juste pour réitérer, le modèle est exactement cela - un modèle pour l'affichage des données. Il devrait être réutilisable, vous devriez être capable de le lier au modèle que vous voulez. Une règle de base - la liaison de données aux données réelles devrait se produire sur le contrôle, pas sur le modèle.

+0

Le code du modèle ne fournit-il pas la liaison? J'ai essayé d'ajouter la ligne de code que vous avez recommandée à l'appel actuel de ItemsControl, mais cela n'a pas aidé . – Vladislav

+0

J'ai manqué ce peu. Jamais essayé de cette façon, semble très gênant. Le modèle est censé définir l'aspect et la convivialité du contrôle, et non les données. –

+0

La ligne dans le modèle s'avère obligatoire, mais doit être remplacée par ItemsSource = "{Binding}". Vous dites que le modèle ne devrait pas fournir de liaison - y at-il un moyen de contourner cela (Autre puis manuellement dans le code C#) – Vladislav