简体   繁体   English

关于WPF绑定的困惑

[英]Confusion about WPF binding

I am trying to bind a 2D array of buttons arranged in stackpanels to a 2D ObservableCollection... 我试图将排列在堆栈面板中的2D按钮数组绑定到2D ObservableCollection ...

Yet, I'm afraid I don't understand something very elementary about binding. 但是,恐怕我对绑定不是很了解。

My XAML: 我的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: 我的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; 
    }
}

The ViewModel: 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 CalendarViewModel.DayNumbers - yet the buttons do not appear. 我正在尝试使用CalendarViewModel.DayNumbers中的值填充按钮-但是按钮没有出现。 I'm clearly doing something wrong with my binding. 我的绑定显然做错了。

Change all your DynamicResource to StaticResource . 将所有DynamicResource更改为StaticResource This shouldn't stop it working, but might be inefficient at runtime. 这不应该停止它的工作,但是可能在运行时效率低下。 Have a look this page for WPF resources overview. 查看此页面以获取WPF资源概述。

Also your ItemsControl is not bound to DayNumbers . 此外,您的ItemsControl也不绑定到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. 在“日历”窗口上设置DataContext时,将设置哪个对象将是整个窗口的默认绑定源。 You didn't specify which property of your ViewModel is bound to the ItemsControl . 您没有指定ViewModel的哪个属性绑定到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. 编辑因为要覆盖ItemsControl的项目模板并在那里提供收集容器,所以还需要为其提供ItemsSource The syntax {Binding} simply means bind to each member or enumeration , in this case ObservableCollection<int> . 语法{Binding}仅表示绑定到每个成员或枚举 ,在本例中为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. 经验法则-绑定到实际数据的数据应在控件而不是模板上发生。

  1. Like Igor said, you need specify ItemsSource={Binding DayNumbers} in outer-most ItemsControl , otherwise, it binds to the DataContext , which is CalendarViewModel and it is not IEnumerable . 就像Igor所说的那样,您需要在最外面的ItemsControl指定ItemsSource={Binding DayNumbers} ,否则,它将绑定到DataContext ,后者是CalendarViewModel ,并且不是IEnumerable

  2. Once you do that, it will apply <DataTemplate x:Key="PanelOfPanels"> for each item inside DayNumbers . 一旦你这样做,它将适用<DataTemplate x:Key="PanelOfPanels">对于内部每个项目DayNumbers Note that the DataContext of the DataTemplate in each element in DayNumbers , which is of type ObservableCollection<int> . 需要注意的是DataContext所述的DataTemplate的每个元素中DayNumbers ,这是类型ObservableCollection<int> Here you cannot specify ItemsSource="{Binding Path=DayNumbers}" as DayNumbers is not a valid property in ObservableCollection<int> . 在这里,您不能指定ItemsSource="{Binding Path=DayNumbers}"因为DayNumbersObservableCollection<int>不是有效的属性。 Instead, since ObservableCollection<int> is already a IEnumerable , it should be fine not specifying ItemsSource since it will by default bind to DataContext . 相反,由于ObservableCollection<int>已经是IEnumerable ,所以最好不指定ItemsSource因为默认情况下它将绑定到DataContext

  3. Finally, it goes to your inner-most <DataTemplate x:Key="ItemsAsButtons"> , and you can put button there as what you did. 最后,它进入最里面的<DataTemplate x:Key="ItemsAsButtons"> ,您可以像执行操作一样在此处放置按钮。

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. 调试WPF绑定并不简单。 One tip is you can use dummy converter and set breakpoint in the Convert method to see what it binds. 一个技巧是您可以使用虚拟转换器并在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}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM