关于WPF绑定的困惑

时间:2010-05-21 01:40:23

标签: c# wpf xaml mvvm binding

我正在尝试将排列在stackpanels中的2D按钮数组绑定到2D ObservableCollection ......

然而,我担心我不明白一些关于约束力的基本内容。

我的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}"/>

我的C#代码: 后端:

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

我正在尝试使用CalendarViewModel.DayNumbers中的值填充按钮 - 但按钮不会出现。我的绑定显然做错了。

2 个答案:

答案 0 :(得分:3)

将您的所有DynamicResource更改为StaticResource。这不应该阻止它工作,但在运行时可能效率低下。查看this page以获取WPF资源概述。

此外,ItemsControl未绑定DayNumbers。像这样添加一个绑定:

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

在日历窗口中设置DataContext时,您将设置哪个对象将成为整个窗口的默认绑定源。您没有指定ViewModel的哪个属性绑定到ItemsControl。这就是上面代码的作用。

编辑由于您要覆盖ItemsControl的项目模板并在其中提供集合容器,因此您还需要为其提供ItemsSource。语法{Binding}仅表示绑定到每个成员或枚举,在本例中为ObservableCollection<int>

重申一下,模板就是 - 用于显示数据的模板。它应该是可重用的,你应该能够将它绑定到你想要的任何模型。经验法则 - 数据绑定到实际数据应该发生在控件上,而不是模板上。

答案 1 :(得分:2)

  1. 像Igor所说,你需要在最外层ItemsSource={Binding DayNumbers}指定ItemsControl,否则,它会绑定到DataContextCalendarViewModel就是IEnumerable不是<DataTemplate x:Key="PanelOfPanels">

  2. 一旦这样做,它将对DayNumbers内的每个项目应用DataContext。请注意DataTemplate中每个元素中DayNumbers的{​​{1}},其类型为ObservableCollection<int>。在此处,您无法指定ItemsSource="{Binding Path=DayNumbers}",因为DayNumbers不是ObservableCollection<int>中的有效属性。相反,由于ObservableCollection<int>已经是IEnumerable,因此不应指定ItemsSource,因为它默认会绑定到DataContext

  3. 最后,它会转到你最内心的<DataTemplate x:Key="ItemsAsButtons">,你可以把按钮放在那里。

  4. 希望它澄清一点。对不起,我没有环境来测试它,并为您提供解决方案。

    调试WPF绑定并不简单。一个提示是你可以使用虚拟转换器并在Convert方法中设置断点来查看它绑定的内容。

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