【问题标题】:WPF Nesting ItemsControlsWPF 嵌套项控件
【发布时间】:2015-09-22 21:58:54
【问题描述】:

我刚刚开始使用 ItemsControls/Binding,但遇到了一个问题。我查看了有关嵌套 ItemsControls 的各种教程,所以我不确定我做错了什么。我相信所有的编码都是正确的,但是 Expander 没有按应有的方式显示内容。 Header 正确地将自身对齐到其父级的顶部,但 ScrollViewer 不会出现,它只会滚动父级“TimeScrollViewer”。我可能是绑定不正确吗?

感谢所有建议。

C#:

private string[][] hours = new string[][]
{
    new string[] { "11:00", "11:30", "12:00", "12:30", "1:00", "1:30", "2:00", "2:30", "3:00", "3:30", "4:00", "4:30", "5:00", "5:30", "6:00", "6:30", "7:00", "7:30", "8:00", "8:30" },
    new string[] { "5:00", "5:30", "6:00", "6:30", "7:00", "7:30", "8:00", "8:30", "9:00" },
    new string[] { "5:00", "5:30", "6:00", "6:30", "7:00", "7:30", "8:00", "8:30", "9:00" },
    new string[] { "5:00", "5:30", "6:00", "6:30", "7:00", "7:30", "8:00", "8:30", "9:00" },
    new string[] { "5:00", "5:30", "6:00", "6:30", "7:00", "7:30", "8:00", "8:30", "9:00" },
    new string[] { "5:00", "5:30", "6:00", "6:30", "7:00", "7:30", "8:00", "8:30", "9:00" },
    new string[] { "5:00", "5:30", "6:00", "6:30", "7:00", "7:30", "8:00", "8:30", "9:00" }
};

public class GuestItem
{
    public string GuestName { get; set; }
}

public class RegistryItem
{
    public string Header { get; set; }
    public List<GuestItem> GuestList = new List<GuestItem>();
}

Expander currentExpander = null;

public MainWindow()
{
    int day = (int)DateTime.Now.DayOfWeek;

    InitializeComponent();

    List<RegistryItem> items = new List<RegistryItem>();

    foreach(string hour in hours[day])
    {
        RegistryItem registryItem = new RegistryItem(){ Header = hour };

        registryItem.GuestList.Add(new GuestItem() { GuestName = "Bob" });
        registryItem.GuestList.Add(new GuestItem() { GuestName = "Frank" });
        registryItem.GuestList.Add(new GuestItem() { GuestName = "Jim" });

        items.Add(registryItem);
    }

    TimeItemsControl.ItemsSource = items;
}

private void ExpanderExpanded(object sender, RoutedEventArgs e)
{
    if(currentExpander != null)
    {
        currentExpander.IsExpanded = false;
    }

    currentExpander = e.Source as Expander;

    currentExpander.IsExpanded = true;
}

private void ExpanderCollapsed(object sender, EventArgs e)
{
    currentExpander = null;
}

XAML:

<s:SurfaceScrollViewer Name="TimeScrollViewer" Grid.Row="1" Grid.Column="1" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Hidden" Background="#4CAAAAFF" Style="{DynamicResource SurfaceScrollViewerHorizontalTop}" Foreground="#4CAAAAFF">
    <ItemsControl Name="TimeItemsControl">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Expander Expanded="ExpanderExpanded" Collapsed="ExpanderCollapsed" Header="{Binding Header}" Style="{DynamicResource SurfaceExpander}" HorizontalContentAlignment="Center" FontSize="21.333" Width="100">
                    <s:SurfaceScrollViewer Width="{Binding ElementName=TimeScrollViewer, Path=ActualWidth}" Height="{Binding ElementName=TimeScrollViewer, Path=ActualHeight}" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Hidden">
                        <ItemsControl ItemsSource="{Binding GuestList}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <s:SurfaceButton Content="{Binding GuestName}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </s:SurfaceScrollViewer>
                </Expander>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</s:SurfaceScrollViewer>

【问题讨论】:

    标签: c# wpf itemscontrol expander


    【解决方案1】:

    当您运行(调试)应用程序并检查 Visual Studio 中的输出选项卡时,您可以多次看到以下输出:

    System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“RegistryItem”(HashCode=15478206)上找不到“GuestList”属性。绑定表达式:路径=访客列表; DataItem='RegistryItem' (HashCode=15478206);目标元素是'ItemsControl'(名称='');目标属性是“ItemsSource”(类型“IEnumerable”)

    因此无法在 RegistryItem 对象上解析到 GuestList 属性的数据绑定。如果仔细查看类型的定义,就会明白原因:

    public class RegistryItem
    {
        public string Header { get; set; }
        public List<GuestItem> GuestList = new List<GuestItem>();
    }
    

    GuestList 不是属性,而是字段。 WPF 绑定引擎需要属性,所以 GuestList 字段尽管是公共的,但绑定引擎不存在,导致上述错误。要解决此问题,只需将其设为属性即可。您可以使用空构造函数来初始化列表:

    public class RegistryItem
    {
        public string Header { get; set; }
        public List<GuestItem> GuestList { get; set; }
    
        public RegistryItem ()
        {
            GuestList = new List<GuestItem>();
        }
    }
    

    然后一切都会正常工作。所以底线是:始终检查错误消息,尤其是绑定错误,它们通常会告诉您可能出了什么问题。由于绑定错误通常是相当隐藏的(因为它们不会破坏东西),您可以使用 [in this other question] 中描述的技术( How can I turn binding errors into runtime exceptions?) 将它们变成完整的异常或至少将它们记录在其他地方。

    【讨论】:

    • 耶!这成功了,非常感谢戳。从现在开始,我会密切关注这些错误!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-29
    • 2020-06-28
    • 2017-07-16
    相关资源
    最近更新 更多