【问题标题】:How to bind ItemsControl (outside a grid) to the a grid?如何将 ItemsControl(网格外)绑定到网格?
【发布时间】:2017-12-04 06:21:01
【问题描述】:

我有一个视图模型,其中包含一个名为 MyLabel 的对象的 ObservableCollection。这些对象有 3 个属性(content、rowNr、columnNr)应该分别绑定到 Content、Grid.Row 和 Grid.Column 属性。

我定义 ItemsControl 的原因是因为它在我的网格中不起作用,即我无法绑定 rowNr 和 columnNr,因为网格 Grid.Column /Grid.Row 属性不断覆盖我的数据。

如何才能使我的标签位于网格内?

<StackPanel>
    <ItemsControl ItemsSource="{Binding Path=MyLabelList}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Label Content="{Binding content}" Grid.Column="{Binding columnNr}" Grid.Row="{Binding rowNr}" Style="{StaticResource MyLabel}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
    </Grid>
</StackPanel>

【问题讨论】:

    标签: c# wpf xaml grid


    【解决方案1】:

    尝试使用Grid 作为ItemsPanelItemsControl

    <ItemsControl ItemsSource="{Binding Path=MyLabelList}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Grid.Column" Value="{Binding columnNr}" />
                <Setter Property="Grid.Row" Value="{Binding rowNr}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Label Content="{Binding content}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    【讨论】:

    • 这不起作用,因为您的标签不在ItemsPanel 的直接内部。
    • 会检查的。看起来很有趣。
    • @Peter:它适用于 ItemContainerStyle。当然,您必须定义 RowDefinitions。
    • 我对实现我不理解的东西有点犹豫,但这对于像我这样的凡人 wpf 用户来说仍然可以。
    • 我认为我不能接受你的回答。再测试一下:)
    【解决方案2】:

    GridItemsControl 一起玩不太好,但您可以参考以下博文:

    使用网格作为 ItemsControl 的面板: http://blog.scottlogic.com/2010/11/15/using-a-grid-as-the-panel-for-an-itemscontrol.html

    另一个选项可能是在视图中“手动”将&lt;RowDefinition&gt;&lt;ColumnDefinition&gt; 元素动态添加到网格中。

    【讨论】:

    • “不要一起玩” - 我经常使用GridItemsControl 来包含多个没有布局关系的项目(例如,可以互相覆盖)。在这种情况下,列/行没有问题,因为您不使用它们。项目的顺序类似于 winforms 中控件的 z 顺序。
    • 好吧,我想它应该是一个具有固定列和行的网格,然后与 ItemsControl 一起玩得不太好:)
    • 这样一个简单的任务看起来真的很复杂,对吧?参考文章
    • 这就是我所说的“不要一起玩得那么好”的意思。如前所述,您最好在视图的代码隐藏中自己创建 元素。
    • 或者,如果您预先知道实际的行数,您可以参考我的第一个答案。
    【解决方案3】:

    您必须在GetContainerForItemOverride() 上以编程方式将绑定设置为ItemContainer

    public class GridItemsControl : ItemsControl
    {
        protected override DependencyObject GetContainerForItemOverride()
        {
            FrameworkElement fwE = base.GetContainerForItemOverride() as FrameworkElement;
            fwE.SetBinding(Grid.ColumnProperty, "columnNr");
            fwE.SetBinding(Grid.RowProperty, "rowNr");
    
            return fwE;
        }
    }
    

    在这样的视图中:

    <custom:GridItemsControl>
        <custom:GridItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <!-- Add here -->
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <!-- Add here -->
                    </Grid.RowDefinitions>
                </Grid>
            </ItemsPanelTemplate>
        </custom:GridItemsControl.ItemsPanel>
    </custom:GridItemsControl>
    

    您还可以实现自己的网格,以生成所需数量的行和列。

    这个伎俩是相当合法的。

    其他信息 您的ItemTemplate 不会直接添加到您的ItemsPanel(在您的情况下为Grid),总是有ContentPresenter 或类似的东西,因为您使用的是DataTemplate。所以你必须这样走。

    为了使其更易于理解,您可以这样想象:

                    <Grid> <!-- This is the ItemsPanel -->
                        <ContentPresenter>
                            <!-- This needs the Binding on Grid.Row, but doesn't know shit without my solution -->
                            <!-- This is your ItemContainer that has the DataContext of your ViewModelItem -->
                            <ContentPresenter.ContentTemplate>
                                <DataTemplate>
                                    <!-- Here is your ItemTemplate -->
                                </DataTemplate>
                            </ContentPresenter.ContentTemplate>
                        </ContentPresenter>
                    </Grid>
    

    【讨论】:

    • 彼得只是我还是这个特定主题是 xaml 更复杂的方面之一?
    • 您的ItemTemplate 不会直接添加到您的ItemsPanel (在您的情况下为Grid)总是有ContentPresenter 或类似的东西,因为您使用的是@987654336 @。所以你必须这样。
    • 谢谢,我试试这个并研究一下。一会儿就接受了
    • 这是否违反了 MVVM?
    • 这里有一个如何在@Clemens 回答中为 ItemsControl 定义 ItemContainerStyle 的示例:stackoverflow.com/questions/22324359/…
    【解决方案4】:

    如果您不想像@Peter 在他的回答中建议的那样子类化ItemsControl,您可以简单地使用ItemsControl.ItemContainerStyle 绑定Grid.ColumnGrid.Row 属性:

    <ItemsControl ItemsSource="{Binding Path=MyLabelList}">
        <ItemsPanelTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <!-- Add here -->
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <!-- Add here -->
                </Grid.RowDefinitions>
            </Grid>
        </ItemsPanelTemplate>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Label Content="{Binding content}" Style="{StaticResource MyLabel}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Grid.Row" Value="{Binding rowNr}" />
                <Setter Property="Grid.Column" Value="{Binding columnNr}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
    

    但是,正如其他人已经提到的,列和行定义不会自动添加,您要么需要在设计时知道它并静态添加它们,要么需要找到某种方法来动态添加它们在运行时。

    【讨论】:

    • 你的意思是什么定义?我正在考虑违反 MVVM 原则来实现这一目标。因为我可以给网格一个 x:Name 并在需要时添加新定义。
    • @Asperger 是的,完全正确。
    • 你会说稍微违反规则不会有害吗?
    • 它不会影响您的代码是否有效,但它可能会影响您和/或其他人的代码维护。
    猜你喜欢
    • 2011-05-28
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多