I am trying to bind a 2D array of buttons arranged in stackpanels to a 2D ObservableCollection...
Yet, I'm afraid I don't understand something very elementary about binding.
My 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}"/>
My C# code: The 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;
}
}
The ViewModel:
class CalendarViewModel
{
CalendarMonth _displayedMonth;
EventCalendar _calendar;
public CalendarViewModel()
{
_displayedMonth = new CalendarMonth();
}
public ObservableCollection<ObservableCollection<int>> DayNumbers
{
get
{
return _displayedMonth.DayNumbers;
}
}
}
I'm trying to populate the buttons with values from Calen开发者_开发知识库darViewModel.DayNumbers - yet the buttons do not appear. I'm clearly doing something wrong with my binding.
Change all your DynamicResource
to StaticResource
. This shouldn't stop it working, but might be inefficient at runtime. Have a look this page for WPF resources overview.
Also your ItemsControl
is not bound to DayNumbers
. Add a binding like so:
<ItemsControl x:Name="DaysPanel" Grid.ColumnSpan="7" Grid.Row="2"
ItemTemplate="{StaticResource PanelOfPanels}"
ItemsSource={Binding DayNumbers}/>
When you set the DataContext
on Calendar window you set which object will be the default binding source for the whole window. You didn't specify which property of your ViewModel is bound to the ItemsControl
. This is what the code above does.
EDIT Because you are overriding the item template for the ItemsControl
and provide a collection container there, you need to provide the ItemsSource
for it as well. The syntax {Binding}
simply means bind to each member or enumeration, in this case ObservableCollection<int>
.
Just to reiterate, the template is exactly that - a template for displaying data. It should be reusable, you should be able to bind it to whatever model you want. A rule of thumb - the data binding to actual data should happen on the control, not the template.
Like Igor said, you need specify
ItemsSource={Binding DayNumbers}
in outer-mostItemsControl
, otherwise, it binds to theDataContext
, which isCalendarViewModel
and it is notIEnumerable
.Once you do that, it will apply
<DataTemplate x:Key="PanelOfPanels">
for each item insideDayNumbers
. Note that theDataContext
of theDataTemplate
in each element inDayNumbers
, which is of typeObservableCollection<int>
. Here you cannot specifyItemsSource="{Binding Path=DayNumbers}"
asDayNumbers
is not a valid property inObservableCollection<int>
. Instead, sinceObservableCollection<int>
is already aIEnumerable
, it should be fine not specifyingItemsSource
since it will by default bind toDataContext
.Finally, it goes to your inner-most
<DataTemplate x:Key="ItemsAsButtons">
, and you can put button there as what you did.
Hope it clarifies a little bit. Sorry I don't have the environment to test it out and give you the solution.
Debugging WPF bindings is not straightforward. One tip is you can use dummy converter and set breakpoint in the Convert
method to see what it binds.
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}}
精彩评论