【问题标题】:How can I databind a list of integers to Grid ColumnDefinitions如何将整数列表数据绑定到 Grid ColumnDefinitions
【发布时间】:2012-06-16 11:26:24
【问题描述】:

我有一组整数:

public ObservableCollection<int> Scores = new ObservableCollection<int> {
    10, 30, 50
};

我希望在绑定时生成类似于以下 XAML 的内容:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="10"/>
        <ColumnDefinition Width="30"/>
        <ColumnDefinition Width="50"/>
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Column="0">10</TextBlock>
    <TextBlock Grid.Column="1">30</TextBlock>
    <TextBlock Grid.Column="2">50</TextBlock>
</Grid>

如何编写数据绑定来执行此操作?

【问题讨论】:

  • 你不能使用 itemsCollection 元素代替特定的文本块吗?
  • @Clueless:几乎可以肯定。我对数据绑定没有真正的经验。我希望数据绑定输出与我发布的 XAML 相同。我不知道如何到达那里。
  • 您只是想在网格中显示一些数据,还是真的想使用集合中的数据设置列的宽度?如果您只想显示数据,为什么不直接使用 DataGrid 并设置 ItemSource?
  • @ReinardMavronicolas:宽度是这里的关键。我对显示数据不太感兴趣。
  • 不确定是否可以绑定列宽。但是,您可以在运行时动态设置列的宽度。循环浏览您的收藏并设置宽度。这应该对您有所帮助:stackoverflow.com/questions/2095124/…

标签: c# silverlight windows-phone-7 data-binding


【解决方案1】:

您可以尝试以下方法:

    <ItemsControl ItemsSource="{Binding Path=Scores}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="Black" BorderThickness="1"
                        Background="Yellow" Width="{Binding}">
                    <TextBlock Text="{Binding}" />
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

我使用的是Border,里面有一个TextBlock,但如果你愿意,你可以用其他东西替换它。重要的是Width 绑定。

还要注意Scores 必须是一个属性。在上面的代码中,您正在创建一个公共字段,但绑定仅适用于属性,而不适用于字段。

编辑:如果您想使用Grid,您可以尝试以下用户控件。此用户控件具有网格宽度的依赖属性,并在每次集合更改时重新创建网格。

using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;

namespace YourNamespace
{
    public partial class BindableGrid : UserControl
    {
        public static readonly DependencyProperty WidthsProperty =
            DependencyProperty.Register("Widths",
                                        typeof(ObservableCollection<int>),
                                        typeof(BindableGrid),
                                        new PropertyMetadata(Widths_Changed));

        public BindableGrid()
        {
            InitializeComponent();
        }

        public ObservableCollection<int> Widths
        {
            get { return (ObservableCollection<int>)GetValue(WidthsProperty); }
            set { SetValue(WidthsProperty, value); }
        }

        private static void Widths_Changed(DependencyObject obj,
                                           DependencyPropertyChangedEventArgs e)
        {
            var grid = obj as BindableGrid;
            if (grid != null)
            {
                grid.OnWidthsChanged(e.OldValue as ObservableCollection<int>);
            }
        }

        private void OnWidthsChanged(ObservableCollection<int> oldValue)
        {
            if (oldValue != null)
            {
                oldValue.CollectionChanged -= Widths_CollectionChanged;
            }

            if (Widths != null)
            {
                Widths.CollectionChanged += Widths_CollectionChanged;
            }

            RecreateGrid();
        }

        private void Widths_CollectionChanged(object sender,
                                              NotifyCollectionChangedEventArgs e)
        {
            // We'll just clear and recreate the entire grid each time
            // the collection changes.
            // Alternatively, you could use e.Action to determine what the
            // actual change was and apply that (e.g. add or delete a
            // single column definition). 
            RecreateGrid();
        }

        private void RecreateGrid()
        {
            // Recreate the column definitions.
            grid.ColumnDefinitions.Clear();
            foreach (int width in Widths)
            {
                // Use new GridLength(1, GridUnitType.Star) for a "*" column.
                var coldef = new ColumnDefinition() { Width = new GridLength(width) };
                grid.ColumnDefinitions.Add(coldef);
            }

            // Now recreate the content of the grid.
            grid.Children.Clear();
            for (int i = 0; i < Widths.Count; ++i)
            {
                int width = Widths[i];
                var textblock = new TextBlock() { Text = width.ToString() };
                Grid.SetColumn(textblock, i);
                grid.Children.Add(textblock);
            }
        }
    }
}

UserControl 的 XAML 仅在 &lt;UserControl&gt; 元素内包含 &lt;Grid x:Name="grid" /&gt;

假设您已将 somePrefix 绑定到命名空间 YourNamespace,您可以按如下方式在 XAML 中使用它:

    <somePrefix:BindableGrid Widths="{Binding Path=Scores}" />

【讨论】:

  • 我实际上是在尝试做一些更复杂的事情,所以我真的需要使用网格。目的是使用交替的网格单元来“对齐”矩形。在蹩脚的 ASCII 艺术中:AAAAAAAA_____BBBBB_____C_____DDDDDD。例如,我可以使用80px*50px*10px*60px 的列宽来实现这一点。这将从 {80, 50, 10, 60} 的 int 数组生成。但是,我认为看如何做简单的案例足以让我解决复杂的案例。
  • @Eric:像这样使用Grid 是一项相当大的工作量。您必须使用代码隐藏在网格中创建列定义。尽管如此,我还是编辑了我的答案,以提供一个示例,说明您可以如何做这样的事情。
猜你喜欢
  • 2013-12-20
  • 2012-07-25
  • 2016-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 2011-10-13
相关资源
最近更新 更多