简体   繁体   English

如何将ItemsControl(网格外部)绑定到网格?

[英]How to bind ItemsControl (outside a grid) to the a grid?

I have a viewmodel which contains an ObservableCollection of objects name MyLabel. 我有一个视图模型,其中包含对象名称MyLabel的ObservableCollection。 These objects have 3 properties (content, rowNr, columnNr) which should be bound to the Content, Grid.Rowand Grid.Column attributes respectively. 这些对象具有3个属性(content,rowNr,columnNr),应分别绑定到Content,Grid.Row和Grid.Column属性。

The reason I defined ItemsControl is because it didnt work inside my grid, that is I couldnt bind rowNr and columnNr since the grids Grid.Column /Grid.Row properties kept overwriting my data. 我定义ItemsControl的原因是因为它在我的网格中不起作用,因为网格Grid.Column /Grid.Row属性一直覆盖我的数据,所以我无法绑定rowNr和columnNr。

How can I make this work so that my labels are inside of the grid? 如何使这项工作有效,以使标签位于网格内?

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

Try to use a Grid as the ItemsPanel for the ItemsControl : 尝试使用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>

You have to set the bindings to the ItemContainer programmaticly on GetContainerForItemOverride() 您必须以编程方式在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;
    }
}

And in the View like this: 在这样的视图中:

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

You could also implement an own grid that generates the wanted amount of rows and columns. 您还可以实现自己的网格,该网格生成所需数量的行和列。

This trick is pretty legit. 这招很合法。

Additional Information Your ItemTemplate will not be directly added to your ItemsPanel (in your case a Grid ) there is allways a ContentPresenter or something like this around, because you are using DataTemplate . 附加信息您的ItemTemplate不会直接添加到ItemsPanel (在您的情况下为Grid ),因为您使用的是DataTemplate ,因此始终存在ContentPresenter或类似的东西。 So you have to go like this. 所以你必须这样走。

To make it more contrihensible you could imagine it like this: 为了使其更容易理解,您可以这样想象:

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

A Grid and ItemsControl don't play that well together but you could refer to the following blog post: GridItemsControl不好,但是您可以参考以下博客文章:

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

Another option may be to "manually" add the <RowDefinition> and <ColumnDefinition> elements to the Grid dynamically in the view. 另一种选择可能是在视图中“手动”将<RowDefinition><ColumnDefinition>元素动态添加到Grid中。

If you don't want to subclass ItemsControl like @Peter suggested in his answer, you could simply use ItemsControl.ItemContainerStyle to bind Grid.Column and Grid.Row properties: 如果您不想像答案中的@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>

But, as others already mentioned, column and row definitions will not be added automatically and you'll either need to know it in design-time and add them statically, or you'll need to find some way to add them dynamically in run-time. 但是,正如其他人已经提到的那样,列和行定义不会自动添加,您要么需要在设计时就知道它并静态添加它们,要么需要找到某种方法在运行时动态添加它们。时间。

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

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