如何在代码中设置固定的列/行定义并在 DesignView 中使用它们

发布于 2024-11-29 03:38:24 字数 296 浏览 1 评论 0原文

我想要具有固定数量的列和行的网格。例如 80 列和 24 行。 在设计视图中,用户不能更改列和行定义,但必须能够将控件插入单元格中。

设计视图应类似于 此 http://imageshack.us/f/29/coldefs.png< /a>

我尝试子类化 Grid 并在构造函数内设置列和行定义,但单元格根本没有显示在 DesignView 中。

这可以做到吗?

I'd like to have Grids with fixed amount of column and rows. 80 columns and 24 rows for example.
In design view, the user must not be able to change the column and row definitions but he must be able to insert controls into the cells.

Design View should look like this http://imageshack.us/f/29/coldefs.png

I tried to subclass Grid and set the Column and Row Definitions inside the constructor, but then the cells did not show up in DesignView at all.

Can this be done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

单挑你×的.吻 2024-12-06 03:38:25

您可以子类化Grid以添加依赖属性RowsColumns,并在PropertyChanged回调中更新RowDefinitions和相应地ColumnDefinitions

要在设计时获取 GridLines,如果处于设计模式,您可以在 Loaded 事件中向每个单元格添加 Border (DesignerProperties.GetIsInDesignMode(this) == true

像这样使用它

<local:FixedSizeGrid Rows="24"
                     Columns="80"
                     Background="#E8E8E8">
    <Button Grid.Row="1" Grid.Column="1"/>
    <Button Grid.Row="1" Grid.Column="2"/>
    <Button Grid.Row="1" Grid.Column="3"/>
</local:FixedSizeGrid>

,设计器中的输出将如下所示。在运行时,您将不会得到任何边框

在此处输入图像描述

编辑
添加和删​​除元素时,Children 属性(即 GridContentProperty)不断在框架中重置。这意味着网格边界也会被清除,据我所知,没有办法通知这一点。为了解决这个问题,我必须将 FixedSizeGridContentProperty 更改为新的 DP,从而更新 Children 和 DesignMode Grid-Borders。

可以进行多种优化,例如每次都清除和读取网格边框。无论如何,这是更新后的代码。它现在应该可以在设计器中工作,如果设置了许多行/列,可能会有点慢,但这可能可以通过一些优化来修复。

固定大小网格

[ContentProperty("ContentChildren")]
public class FixedSizeGrid : Grid
{
    #region Dependency Properties

    public static readonly DependencyProperty RowsProperty =
        DependencyProperty.Register("Rows",
                                    typeof(int),
                                    typeof(FixedSizeGrid),
                                    new FrameworkPropertyMetadata(24, RowsPropertyChanged));
    public static readonly DependencyProperty ColumnsProperty =
        DependencyProperty.Register("Columns",
                                    typeof(int),
                                    typeof(FixedSizeGrid),
                                    new FrameworkPropertyMetadata(80, ColumnsPropertyChanged));
    public static readonly DependencyProperty ContentChildrenProperty =
        DependencyProperty.Register("ContentChildren",
                                    typeof(ObservableCollection<UIElement>),
                                    typeof(FixedSizeGrid),
                                    new FrameworkPropertyMetadata(new ObservableCollection<UIElement>()));

    #endregion // Dependency Properties

    #region Properties

    private static void RowsPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        FixedSizeGrid fixedSizeGrid = sender as FixedSizeGrid;
        fixedSizeGrid.UpdateRowDefinitions();
    }
    private static void ColumnsPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        FixedSizeGrid fixedSizeGrid = sender as FixedSizeGrid;
        fixedSizeGrid.UpdateColumnDefinitions();
    }
    public ObservableCollection<UIElement> ContentChildren
    {
        get { return (ObservableCollection<UIElement>)GetValue(ContentChildrenProperty); }
        set { SetValue(ContentChildrenProperty, value); }
    }

    public int Rows
    {
        get { return (int)GetValue(RowsProperty); }
        set { SetValue(RowsProperty, value); }
    }
    public int Columns
    {
        get { return (int)GetValue(ColumnsProperty); }
        set { SetValue(ColumnsProperty, value); }
    }

    #endregion // Properties

    #region Fields

    private List<Border> m_designTimeBorders;

    #endregion //Fields

    #region Constructor

    public FixedSizeGrid()
    {
        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            m_designTimeBorders = new List<Border>();
        }

        SnapsToDevicePixels = true;
        Loaded += FixedSizeGrid_Loaded;
        ContentChildren.CollectionChanged += ContentChildren_CollectionChanged;
    }

    #endregion // Constructor

    #region Event Handlers

    private void FixedSizeGrid_Loaded(object sender, RoutedEventArgs e)
    {
        UpdateRowDefinitions();
        UpdateColumnDefinitions();
    }

    private void ContentChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (UIElement element in e.NewItems)
            {
                RemoveFromParent(element);
                Children.Add(element);
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (UIElement element in e.OldItems)
            {
                Children.Remove(element);
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Reset)
        {
            Children.Clear();
        }
        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            AddDesignTimeBorders();
        }
    }

    #endregion // Event Handlers

    #region Private Methods

    private void RemoveFromParent(UIElement element)
    {
        DependencyObject parent = element;
        while (parent != null && !(parent is FixedSizeGrid))
        {
            parent = LogicalTreeHelper.GetParent(parent);
        }
        if (parent != null)
        {
            (parent as FixedSizeGrid).Children.Remove(element);
        }
    }

    private void UpdateRowDefinitions()
    {
        while (RowDefinitions.Count > Rows && RowDefinitions.Count > 0)
            RowDefinitions.Remove(RowDefinitions[RowDefinitions.Count-1]);
        while (RowDefinitions.Count < Rows)
            RowDefinitions.Add(new RowDefinition());

        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            AddDesignTimeBorders();
        }
    }
    private void UpdateColumnDefinitions()
    {
        while (ColumnDefinitions.Count > Columns && ColumnDefinitions.Count > 0)
            ColumnDefinitions.Remove(ColumnDefinitions[ColumnDefinitions.Count - 1]);
        while (ColumnDefinitions.Count < Columns)
            ColumnDefinitions.Add(new ColumnDefinition());

        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            AddDesignTimeBorders();
        }
    }

    private void AddDesignTimeBorders()
    {
        RemoveDesignTimeBorders();
        for (int row = 0; row < Rows; row++)
        {
            for (int column = 0; column < Columns; column++)
            {
                Border designTimeBorder = new Border();
                designTimeBorder.Tag = "DesignTimeBorder";
                designTimeBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(154, 191, 229));
                designTimeBorder.BorderThickness = new Thickness(0,0,1,1);
                Grid.SetRow(designTimeBorder, row);
                Grid.SetColumn(designTimeBorder, column);
                m_designTimeBorders.Add(designTimeBorder);
            }
        }
        foreach (Border designTimeBorder in m_designTimeBorders)
        {
            Children.Add(designTimeBorder);
        }
    }
    private void RemoveDesignTimeBorders()
    {
        foreach (Border designTimeBorder in m_designTimeBorders)
        {
            Children.Remove(designTimeBorder);
        }
        m_designTimeBorders.Clear();
    }

    #endregion // Private Methods
}

You could subclass Grid to add the dependency properties Rows and Columns and in the PropertyChanged callback you update the RowDefinitions and ColumnDefinitions accordingly.

To get GridLines in design time you can add a Border to each cell in the Loaded event if you are in Design Mode (DesignerProperties.GetIsInDesignMode(this) == true)

Use it like this

<local:FixedSizeGrid Rows="24"
                     Columns="80"
                     Background="#E8E8E8">
    <Button Grid.Row="1" Grid.Column="1"/>
    <Button Grid.Row="1" Grid.Column="2"/>
    <Button Grid.Row="1" Grid.Column="3"/>
</local:FixedSizeGrid>

And the output in the designer will look like below. In runtime you'll get no Borders.

enter image description here

Edit
The Children Property (which is the ContentProperty for Grid) keeps getting reset in the framework when adding and removing elements. This means that the Grid-Borders get wiped clean as well and there is no way to be notified about this as far as I can tell. To work around this I had to change the ContentProperty of FixedSizeGrid to a new DP which in turn updates both Children and the DesignMode Grid-Borders.

There are several optimizations that can be made, clearing and readding the Grid-Borders everytime for example. Anyway, here is the updated code. It should work in the designer now, perhaps a little slow if many rows/columns are set but this can probably be fixed with some optimizations.

FixedSizeGrid

[ContentProperty("ContentChildren")]
public class FixedSizeGrid : Grid
{
    #region Dependency Properties

    public static readonly DependencyProperty RowsProperty =
        DependencyProperty.Register("Rows",
                                    typeof(int),
                                    typeof(FixedSizeGrid),
                                    new FrameworkPropertyMetadata(24, RowsPropertyChanged));
    public static readonly DependencyProperty ColumnsProperty =
        DependencyProperty.Register("Columns",
                                    typeof(int),
                                    typeof(FixedSizeGrid),
                                    new FrameworkPropertyMetadata(80, ColumnsPropertyChanged));
    public static readonly DependencyProperty ContentChildrenProperty =
        DependencyProperty.Register("ContentChildren",
                                    typeof(ObservableCollection<UIElement>),
                                    typeof(FixedSizeGrid),
                                    new FrameworkPropertyMetadata(new ObservableCollection<UIElement>()));

    #endregion // Dependency Properties

    #region Properties

    private static void RowsPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        FixedSizeGrid fixedSizeGrid = sender as FixedSizeGrid;
        fixedSizeGrid.UpdateRowDefinitions();
    }
    private static void ColumnsPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        FixedSizeGrid fixedSizeGrid = sender as FixedSizeGrid;
        fixedSizeGrid.UpdateColumnDefinitions();
    }
    public ObservableCollection<UIElement> ContentChildren
    {
        get { return (ObservableCollection<UIElement>)GetValue(ContentChildrenProperty); }
        set { SetValue(ContentChildrenProperty, value); }
    }

    public int Rows
    {
        get { return (int)GetValue(RowsProperty); }
        set { SetValue(RowsProperty, value); }
    }
    public int Columns
    {
        get { return (int)GetValue(ColumnsProperty); }
        set { SetValue(ColumnsProperty, value); }
    }

    #endregion // Properties

    #region Fields

    private List<Border> m_designTimeBorders;

    #endregion //Fields

    #region Constructor

    public FixedSizeGrid()
    {
        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            m_designTimeBorders = new List<Border>();
        }

        SnapsToDevicePixels = true;
        Loaded += FixedSizeGrid_Loaded;
        ContentChildren.CollectionChanged += ContentChildren_CollectionChanged;
    }

    #endregion // Constructor

    #region Event Handlers

    private void FixedSizeGrid_Loaded(object sender, RoutedEventArgs e)
    {
        UpdateRowDefinitions();
        UpdateColumnDefinitions();
    }

    private void ContentChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (UIElement element in e.NewItems)
            {
                RemoveFromParent(element);
                Children.Add(element);
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (UIElement element in e.OldItems)
            {
                Children.Remove(element);
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Reset)
        {
            Children.Clear();
        }
        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            AddDesignTimeBorders();
        }
    }

    #endregion // Event Handlers

    #region Private Methods

    private void RemoveFromParent(UIElement element)
    {
        DependencyObject parent = element;
        while (parent != null && !(parent is FixedSizeGrid))
        {
            parent = LogicalTreeHelper.GetParent(parent);
        }
        if (parent != null)
        {
            (parent as FixedSizeGrid).Children.Remove(element);
        }
    }

    private void UpdateRowDefinitions()
    {
        while (RowDefinitions.Count > Rows && RowDefinitions.Count > 0)
            RowDefinitions.Remove(RowDefinitions[RowDefinitions.Count-1]);
        while (RowDefinitions.Count < Rows)
            RowDefinitions.Add(new RowDefinition());

        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            AddDesignTimeBorders();
        }
    }
    private void UpdateColumnDefinitions()
    {
        while (ColumnDefinitions.Count > Columns && ColumnDefinitions.Count > 0)
            ColumnDefinitions.Remove(ColumnDefinitions[ColumnDefinitions.Count - 1]);
        while (ColumnDefinitions.Count < Columns)
            ColumnDefinitions.Add(new ColumnDefinition());

        if (DesignerProperties.GetIsInDesignMode(this) == true)
        {
            AddDesignTimeBorders();
        }
    }

    private void AddDesignTimeBorders()
    {
        RemoveDesignTimeBorders();
        for (int row = 0; row < Rows; row++)
        {
            for (int column = 0; column < Columns; column++)
            {
                Border designTimeBorder = new Border();
                designTimeBorder.Tag = "DesignTimeBorder";
                designTimeBorder.BorderBrush = new SolidColorBrush(Color.FromRgb(154, 191, 229));
                designTimeBorder.BorderThickness = new Thickness(0,0,1,1);
                Grid.SetRow(designTimeBorder, row);
                Grid.SetColumn(designTimeBorder, column);
                m_designTimeBorders.Add(designTimeBorder);
            }
        }
        foreach (Border designTimeBorder in m_designTimeBorders)
        {
            Children.Add(designTimeBorder);
        }
    }
    private void RemoveDesignTimeBorders()
    {
        foreach (Border designTimeBorder in m_designTimeBorders)
        {
            Children.Remove(designTimeBorder);
        }
        m_designTimeBorders.Clear();
    }

    #endregion // Private Methods
}
如若梦似彩虹 2024-12-06 03:38:25

如果您想查看单元格或方块,可以将 ShowGridLines 属性设置为 true

You can set ShowGridLines property to true if you want to see the cell or squares

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文