为WPF和Silverlight的Grid添加边框线(zz)

 

Grid是WPF和Silverlight中的一个重要的布局元素,其他的布局元素还有StackPanel, Canvas, Border等等。从字面上说,Grid是一个表格的意思,它的使用也确实很方便,从视觉上很像一个表格的样式,有行,有列的概念,这种效果很适合于需要多多个子控件进行布局,并希望保持左边或者上对齐的效果。

我们来看一个最简单的例子(本文采用Silverlight做演示,在WPF中也是一样的)

使用Grid的时候,一般先定义Grid的行和列的设置,然后在其放置其他控件并且设置他们的行号和列号即可,语法和语义都很简单和清晰

<UserControl
    x:Class="SilverlightApplicationGridBorderSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">

        <Grid.Resources>
            <Style
                TargetType="TextBlock">
                <Setter
                    Property="FontSize"
                    Value="30"></Setter>
                <Setter
                    Property="VerticalAlignment"
                    Value="Center"></Setter>
            </Style>
        </Grid.Resources>

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <TextBlock
            Text="左上角"></TextBlock>
        <TextBlock
            Text="左下角"
            Grid.Row="1"></TextBlock>

        <TextBlock
            Text="右上角"
            Grid.Column="1"></TextBlock>

        <TextBlock
            Text="右下角"
            Grid.Row="1"
            Grid.Column="1"></TextBlock>
    </Grid>
</UserControl>

嗯,看起来很好理解的。但是,几乎所有人(包括我在内)在最开始学习的时候,马上就会想到一个问题:

既然是用一个表格形状进行布局了,那么能不能显示出来表格的边框线呢

没想到这会是一个问题,对吧?或者你想到过了,但没有找到如何解决这个问题。

如果是这样,那么请继续往下看吧

本文完整源代码,可以通过这里下载

http://files.cnblogs.com/chenxizhang/SilverlightApplicationGridBorderSample.rar

第一步:使用ShowGridLines属性

根据经验,我们会先从Grid这个元素上面去想办法。我们确实可以找到一个与我们需求很相近的属性:ShowGridLines,好吧,将它设为true之后,会怎么样呢

<UserControl
    x:Class="SilverlightApplicationGridBorderSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White" ShowGridLines="True" >

        <Grid.Resources>
            <Style
                TargetType="TextBlock">
                <Setter
                    Property="FontSize"
                    Value="30"></Setter>
                <Setter
                    Property="VerticalAlignment"
                    Value="Center"></Setter>
            </Style>
        </Grid.Resources>

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <TextBlock
            Text="左上角"></TextBlock>
        <TextBlock
            Text="左下角"
            Grid.Row="1"></TextBlock>

        <TextBlock
            Text="右上角"
            Grid.Column="1"></TextBlock>

        <TextBlock
            Text="右下角"
            Grid.Row="1"
            Grid.Column="1"></TextBlock>
    </Grid>
</UserControl>

哦,看起来确实有边框了。但是,效果却不理想。这个边框线是虚线,坦白说,不是那么好看。从MSDN文档中我们了解到,这个边框线只是用来辅助我们做调试用的,而不适宜于在真正的产品中用。

私下里说,我并不认为这是一个好的设计,为什么不提供实线(甚至可以由开发人员配置)的边框呢

第二步:使用手工定义的方式实现Grid边框线

我们希望给Grid自动添加边框,应该怎么实现呢?其实,如果仅仅是给一个Grid添加的话,手工写一点代码就可以了

<UserControl
    x:Class="SilverlightApplicationGridBorderSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">

        <Grid.Resources>
            <Style
                TargetType="TextBlock">
                <Setter
                    Property="FontSize"
                    Value="30"></Setter>
                <Setter
                    Property="VerticalAlignment"
                    Value="Center"></Setter>
            </Style>
            <Style
                TargetType="Border">
                <Setter
                    Property="BorderBrush"
                    Value="LightGray"></Setter>
                <Setter
                    Property="BorderThickness"
                    Value="1"></Setter>
            </Style>
        </Grid.Resources>

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <TextBlock
            Text="左上角"></TextBlock>
        <TextBlock
            Text="左下角"
            Grid.Row="1"></TextBlock>

        <TextBlock
            Text="右上角"
            Grid.Column="1"></TextBlock>

        <TextBlock
            Text="右下角"
            Grid.Row="1"
            Grid.Column="1"></TextBlock>

        <!--添加4个边框-->
        <Border></Border>
        <Border
            Grid.Row="1"></Border>
        <Border
            Grid.Column="1"></Border>
        <Border
            Grid.Row="1"
            Grid.Column="1"></Border>
    </Grid>
</UserControl>

所以,其实我们可以手工添加Border(文章开头提到几个布局元素中,只有Border有边框线)实现我们的需求。

但问题在于,如果有很多Grid,都要这么去添加总是不好的吧,有没有办法更好地实现这样功能呢

第三步:使用附加依赖属性(Attached Dependency Property)实现Grid边框线

既然官方并没有提供我们需要的边框线,那么我们就自己来实现一个吧。事实上,这并没有多难,尤其是你理解了WPF和Silvelight中一些核心的概念的情况下,这些概念包括依赖属性附加依赖属性

对这两个概念,大家可以参考上面我给出的两个链接,这里我就简单地说几句吧,

依赖属性(Dependency Property)是WPF和Silverlight较之前的编程模型的一个核心改变,它使得基于绑定的编程变得可能,这个大家多少有些体会了,在WPF和Silverlight中,绑定无处不在,而且功能确实强大,尤其是双向绑定及自动通知,减少了很多很多的用户代码。

附加属性(Attached Property),则是另外一种场景,它一般用来对现有控件或者元素进行扩展。其实,我们之前的XAML中已经用到了附加属性,请看下面的部分

        <TextBlock
            Text="右下角"
            Grid.Row="1"
            Grid.Column="1"></TextBlock>

TextBlock这个元素,其实并没有行和列的概念,或者说它也不需要,除非它是放在一个Grid里面的时候。所以,行和列并不是TextBlock的属性,但是如果将它放在Grid里面,不提供这些信息又不行,所以附加属性就应运而生了。Grid.Row和Grid.Column就是附加属性,很显然,有了附加属性,我们就可以在不改变TextBlock的前提下,为它添加很多特性或者功能。

理解了附加属性,我们来说说现在我们要解决的问题:

我们能不能自动给每个Grid添加一个属性,让它可以为自己添加必要的边框线呢?

答案就是附加属性。

请添加一个代码文件,将下面代码粘贴进去

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SilverlightApplicationGridBorderSample
{
    /// <summary>
    /// 为Grid添加的一个特殊功能
    /// 作者:陈希章
    /// 反馈:[email protected]
    /// </summary>
    public class GridHelper
    {

        //请注意:可以通过propa这个快捷方式生成下面三段代码

        public static bool GetShowBorder(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBorderProperty);
        }

        public static void SetShowBorder(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBorderProperty, value);
        }

        public static readonly DependencyProperty ShowBorderProperty =
            DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridHelper), new PropertyMetadata(OnShowBorderChanged));

        //这是一个事件处理程序,需要手工编写,必须是静态方法
        private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as Grid;
            if((bool)e.OldValue)
            {
                grid.Loaded -= (s, arg) => { };
            }
            if((bool)e.NewValue)
            {
                grid.Loaded += (s, arg) =>
                {
                    //确定行和列数
                    var rows = grid.RowDefinitions.Count;
                    var columns = grid.ColumnDefinitions.Count;

                    //每个格子添加一个Border进去
                    for(int i = 0; i < rows; i++)
                    {
                        for(int j = 0; j < columns; j++)
                        {
                            var border = new Border() { BorderBrush = new SolidColorBrush(Colors.Gray), BorderThickness = new Thickness(1) };
                            Grid.SetRow(border, i);
                            Grid.SetColumn(border, j);

                            grid.Children.Add(border);
                        }
                    }

                };
            }

        }

    }

}

上面的代码应该很好理解,我们是用代码实现了与手工添加Border一样的功能,奥妙在于,Grid有一个Loaded事件,我们完全可以在这个事件里面,根据计算得到的行和列去添加Border。

如何在页面中使用我们附加属性呢?我们需要在XAML中稍做修改

<UserControl
    x:Class="SilverlightApplicationGridBorderSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"
    xmlns:ext="clr-namespace:SilverlightApplicationGridBorderSample">

    <Grid
        ext:GridHelper.ShowBorder="True"
        x:Name="LayoutRoot"
        Background="White">

        <Grid.Resources>
            <Style
                TargetType="TextBlock">
                <Setter
                    Property="FontSize"
                    Value="30"></Setter>
                <Setter
                    Property="VerticalAlignment"
                    Value="Center"></Setter>
            </Style>
        </Grid.Resources>

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <TextBlock
            Text="左上角"></TextBlock>
        <TextBlock
            Text="左下角"
            Grid.Row="1"></TextBlock>

        <TextBlock
            Text="右上角"
            Grid.Column="1"></TextBlock>

        <TextBlock
            Text="右下角"
            Grid.Row="1"
            Grid.Column="1"></TextBlock>
    </Grid>
</UserControl>

请注意,我们只需要导入命名空间,然后在Grid上面设置ext:GridHelper.ShowBorder="True" 即可。这就是附加属性的神奇之处

看起来不错对吧?先不要着急,看看另外一个情况,加入我们希望把第一行的两列进行合并(ColumnSpan)的话,会怎么样呢?

<UserControl
    x:Class="SilverlightApplicationGridBorderSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"
    xmlns:ext="clr-namespace:SilverlightApplicationGridBorderSample">

    <Grid
        ext:GridHelper.ShowBorder="True"
        x:Name="LayoutRoot"
        Background="White">

        <Grid.Resources>
            <Style
                TargetType="TextBlock">
                <Setter
                    Property="FontSize"
                    Value="30"></Setter>
                <Setter
                    Property="VerticalAlignment"
                    Value="Center"></Setter>
            </Style>
        </Grid.Resources>

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <TextBlock
            Text="第一行合并两个列的内容" Grid.ColumnSpan="2"></TextBlock>
        <TextBlock
            Text="左下角"
            Grid.Row="1"></TextBlock>

        <TextBlock
            Text="右下角"
            Grid.Row="1"
            Grid.Column="1"></TextBlock>
    </Grid>
</UserControl>
 
 

我们看到,虽然确实第一行是合并了,但是边框线却仍然有两个,也就是说,我们在添加Border的时候,没有考虑到行或者列合并的情况。这样就不是特别理想了。我们下面要改进这个属性。

第四步:改进附加属性适应行和列的合并情况

请注意,将代码做如下的改动

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SilverlightApplicationGridBorderSample
{
    /// <summary>
    /// 为Grid添加的一个特殊功能
    /// 作者:陈希章
    /// 反馈:[email protected]
    /// </summary>
    public class GridHelper
    {

        //请注意:可以通过propa这个快捷方式生成下面三段代码

        public static bool GetShowBorder(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBorderProperty);
        }

        public static void SetShowBorder(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBorderProperty, value);
        }

        public static readonly DependencyProperty ShowBorderProperty =
            DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridHelper), new PropertyMetadata(OnShowBorderChanged));

        //这是一个事件处理程序,需要手工编写,必须是静态方法
        private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as Grid;
            if((bool)e.OldValue)
            {
                grid.Loaded -= (s, arg) => { };
            }
            if((bool)e.NewValue)
            {
                grid.Loaded += (s, arg) =>
                {
                    //改进后的做法,不是简单地根据行和列,而是根据Grid的顶层子控件的个数去添加边框,同时考虑合并的情况
                    var controls = grid.Children;
                    var count = controls.Count;

                    for(int i = 0; i < count; i++)
                    {
                        var item = controls[i] as FrameworkElement;
                        var border = new Border()
                        {
                            BorderBrush = new SolidColorBrush(Colors.LightGray),
                            BorderThickness = new Thickness(1)
                        };

                        var row = Grid.GetRow(item);
                        var column = Grid.GetColumn(item);
                        var rowspan = Grid.GetRowSpan(item);
                        var columnspan = Grid.GetColumnSpan(item);

                        Grid.SetRow(border, row);
                        Grid.SetColumn(border, column);
                        Grid.SetRowSpan(border, rowspan);
                        Grid.SetColumnSpan(border, columnspan);

                        grid.Children.Add(border);

                    }

                };
            }

        }

    }

}

改动之后的效果明显比较理想了,它考虑到了行和列的合并的情况。那么,事情结束了么?先不要着急,我们再来做一个事情,假设我们希望每个单元格中的内容都与边框(左,上,右,下)有一定的距离,怎么实现呢?

我们会自然联想到,给Border设置Padding属性就可以了吧,那么试试吧

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SilverlightApplicationGridBorderSample
{
    /// <summary>
    /// 为Grid添加的一个特殊功能
    /// 作者:陈希章
    /// 反馈:[email protected]
    /// </summary>
    public class GridHelper
    {

        //请注意:可以通过propa这个快捷方式生成下面三段代码

        public static bool GetShowBorder(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBorderProperty);
        }

        public static void SetShowBorder(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBorderProperty, value);
        }

        public static readonly DependencyProperty ShowBorderProperty =
            DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridHelper), new PropertyMetadata(OnShowBorderChanged));

        //这是一个事件处理程序,需要手工编写,必须是静态方法
        private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as Grid;
            if((bool)e.OldValue)
            {
                grid.Loaded -= (s, arg) => { };
            }
            if((bool)e.NewValue)
            {
                grid.Loaded += (s, arg) =>
                {
                    //改进后的做法,不是简单地根据行和列,而是根据Grid的顶层子控件的个数去添加边框,同时考虑合并的情况
                    var controls = grid.Children;
                    var count = controls.Count;

                    for(int i = 0; i < count; i++)
                    {
                        var item = controls[i] as FrameworkElement;
                        var border = new Border()
                        {
                            BorderBrush = new SolidColorBrush(Colors.LightGray),
                            BorderThickness = new Thickness(1),
                            Padding= new Thickness(10)
                        };

                        var row = Grid.GetRow(item);
                        var column = Grid.GetColumn(item);
                        var rowspan = Grid.GetRowSpan(item);
                        var columnspan = Grid.GetColumnSpan(item);

                        Grid.SetRow(border, row);
                        Grid.SetColumn(border, column);
                        Grid.SetRowSpan(border, rowspan);
                        Grid.SetColumnSpan(border, columnspan);

                        grid.Children.Add(border);

                    }

                };
            }

        }

    }

}

看起来是可以的,但是运行起来,情况好像没有什么变化。我们的文字与边框仍然没有任何距离。

这是为什么呢?既然Border设置了Padding属性,那么又为什么实现不了我们需要的效果呢?

其实很简单,Border的Padding属性只影响它内部的子元素或者控件。我们上面的代码,只是创建了Border,并且将其添加到Grid的Chiildren里面去。但并没有将那些TextBlock移动到Border里面去,所以就实现不了Padding效果了。

第五步:移动TextBlock到相应的Border

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SilverlightApplicationGridBorderSample
{
    /// <summary>
    /// 为Grid添加的一个特殊功能
    /// 作者:陈希章
    /// 反馈:[email protected]
    /// </summary>
    public class GridHelper
    {

        //请注意:可以通过propa这个快捷方式生成下面三段代码

        public static bool GetShowBorder(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBorderProperty);
        }

        public static void SetShowBorder(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBorderProperty, value);
        }

        public static readonly DependencyProperty ShowBorderProperty =
            DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridHelper), new PropertyMetadata(OnShowBorderChanged));

        //这是一个事件处理程序,需要手工编写,必须是静态方法
        private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as Grid;
            if((bool)e.OldValue)
            {
                grid.Loaded -= (s, arg) => { };
            }
            if((bool)e.NewValue)
            {
                grid.Loaded += (s, arg) =>
                {

                    //这种做法自动将控件移动到Border里面来
                    var controls = grid.Children;
                    var count = controls.Count;

                    for(int i = 0; i < count; i++)
                    {
                        var item = controls[i] as FrameworkElement;
                        var border = new Border()
                        {
                            BorderBrush = new SolidColorBrush(Colors.LightGray),
                            BorderThickness = new Thickness(1),
                            Padding = new Thickness(20)
                        };

                        var row = Grid.GetRow(item);
                        var column = Grid.GetColumn(item);
                        var rowspan = Grid.GetRowSpan(item);
                        var columnspan = Grid.GetColumnSpan(item);

                        Grid.SetRow(border, row);
                        Grid.SetColumn(border, column);
                        Grid.SetRowSpan(border, rowspan);
                        Grid.SetColumnSpan(border, columnspan);

                        grid.Children.RemoveAt(i);
                        border.Child = item;
                        grid.Children.Insert(i, border);

                    }
                };
            }

        }

    }

}

为了大家看到效果,我将Padding设置为20. 请注意,上述代码中,我们先从Grid中移除掉了有关的控件,然后将这些控件添加到Border里面去了。此所谓移花接木也。大家可以看到,现在每个格子里面的内容都与边框有一定的距离了。

本文完整源代码,可以通过这里下载

http://files.cnblogs.com/chenxizhang/SilverlightApplicationGridBorderSample.rar

总结:

本文采用循序渐进的方式演示了如何为Grid元素添加边框线的功能,从最原始的手工方式,逐渐演化到最后的解决方案。通过本文,你可以学会这个具体的场景问题解决方法,更可以体会到如何通过附加属性实现更多特殊的功能。

分类: WPF或者Silverligh

绿色通道: 好文要顶 关注我 收藏该文与我联系

陈希章

关注 - 2

粉丝 - 1371

荣誉:推荐博客

+加关注

13

1

(请您对文章做出评价)

?上一篇:你得学会并且学得会的Socket编程基础知识(续)——Silverlight客户端

?下一篇:参照WPF实现Silverlight中的多值绑定特性

posted on 2011-09-22 19:01 陈希章 阅读(14158) 评论(30) 编辑 收藏

评论
#1楼 2011-09-22 19:15 东东

有两个缺陷:(1)效果出来后是最少是双线(Thickness=1,两个Border相邻=2),需要改变算法实现单线

(2)无法单独控制Border四边的颜色

支持(1)反对(0)

回复引用

#2楼[楼主] 2011-09-22 19:17 陈希章

我已经将这个扩展上传到nuget gallery,请通过下面地址查看

http://nuget.org/List/Packages/WPFSilverlightExtension/1.0

在visual studio中,可以直接使用,请打开nuget package explorer中,搜索在线资源中的"wpfsilverlightextension"即可

如果在silverlight中使用,则导入

xmlns:ext="clr-namespace:System.Windows;assembly=SilverlightExtension"

如果在WPF中使用,则导入

xmlns:ext="clr-namespace:System.Windows;assembly=WPFExtension"

关于如何使用unget package,请参考

http://www.cnblogs.com/dudu/archive/2011/07/15/nuget.html

支持(0)反对(0)

回复引用

#3楼[楼主] 2011-09-22 19:17 陈希章

引用东东:

有两个缺陷:(1)效果出来后是最少是双线(Thickness=1,两个Border相邻=2),需要改变算法实现单线

(2)无法单独控制Border四边的颜色

呵呵,你有没有兴趣修改一下呢

支持(0)反对(0)

回复引用

#4楼 2011-09-22 20:35 JasenKin

思路不错,顶一下

支持(0)反对(0)

回复引用

#5楼 2011-09-22 21:45 东东

@陈希章

已经实现了,是一个基于SL的可视化快速开发平台(还有拖动单元格合并/拆分、线条色彩、单元格字体等等),由于是商业项目,不方便公布。

支持(0)反对(0)

回复引用

#6楼[楼主] 2011-09-22 23:26 陈希章

@东东

好的,没问题,要实现并不难。探讨思路是本文的主要目的

支持(0)反对(0)

回复引用

#7楼 2011-09-22 23:54 Muse

这才是纯粹的WPF开发思路。

我都是用Border直接在Grid里画...

支持(0)反对(0)

回复引用

#8楼 2011-09-23 08:56 LiangHu

真棒的文章,

支持(0)反对(0)

回复引用

#9楼 2011-09-23 09:54 如是如是

好文章

支持(0)反对(0)

回复引用

#10楼[楼主] 2011-09-23 11:33 陈希章

@Muse

@LiangHu

@如是如是

呵呵,谢谢支持

支持(0)反对(0)

回复引用

#11楼 2011-09-25 11:36 zjyuan

非常棒、思路的引导比技能的传授更加有意义。

支持(0)反对(0)

回复引用

#12楼[楼主] 2011-09-25 12:28 陈希章

@zjyuan

是的,思路很重要

支持(0)反对(0)

回复引用

#13楼 2011-09-29 16:44 笨笨蜗牛

引用东东:

@陈希章

已经实现了,是一个基于SL的可视化快速开发平台(还有拖动单元格合并/拆分、线条色彩、单元格字体等等),由于是商业项目,不方便公布。

技术讨论而已,干吗冠以“商业项目”的名目?我想,既然你已经实现了,那是可以把其中的一段实现的代码SHOW出来的。

呵呵,一家之言。

支持(0)反对(0)

回复引用

#14楼 2011-09-29 16:48 笨笨蜗牛

思路很好,确实是值得借鉴并引发思路的扩展。

不过,这里在解决问题的时候,局限于数据布局的GRID,也就是一个CELL或者CELLSPAN里只放一个UI对象。假如是在UI设计里来使用,一个CELL里可能放几个UI对象,而且,可能存在交叉(比如A放CELL1,B放CELL2,C则使用CELLSPAN放在CELL1和CELL2里),此时又该如何解决?

此外,通过BORDER的方式来绘制线条,如东东所言,存在重复的可能,并且外边框(姑且不谈四条边分别控制)和内线条都不好控制。

我也在想找个时间实现这个效果,但。。。如果东东能把这个实现技术公布出来,将非常感谢。。。有现成的,还是寄希望于“拿来主义”。期待ing!

支持(0)反对(0)

回复引用

#15楼 2011-09-29 16:51 笨笨蜗牛

再补充个需求:如果能控制CELLPADDING和CELLMARGIN如何?

支持(0)反对(0)

回复引用

#16楼 2011-09-30 16:32 东东

单线条控制,可以采用Border,边线宽度设置为1:

(1)所有的单元格设置显示“右”“下”边线

(2)第一行增加显示“上”边线

(3)第一列增加显示“左”边线

支持(0)反对(0)

回复引用

#17楼[楼主] 2011-09-30 19:12 陈希章

@笨笨蜗牛

我建议你可以尝试一下

支持(0)反对(0)

回复引用

#18楼 2011-10-03 11:56 DecleorMX

感觉性能应该不会很好吧。。还需要将Control一个个的挪动。

支持(0)反对(0)

回复引用

#19楼 2011-10-15 00:26 wl11211[未注册用户]

引用东东:

单线条控制,可以采用Border,边线宽度设置为1:

(1)所有的单元格设置显示“右”“下”边线

(2)第一行增加显示“上”边线

(3)第一列增加显示“左”边线

可否说说 拖动合并单元格的思路?

回复引用

#20楼 2012-02-13 16:36 鲁家宏

支持陈老师,找资料又找到你博客了!·

支持(0)反对(0)

回复引用

#21楼 2012-07-14 14:53 异想天开的妄想狂

真感谢这位老师 解决的问题发昂是太细致了!

支持(0)反对(0)

回复引用

#22楼 2012-11-22 15:35 程序员蛋子

很好,对我有用

支持(0)反对(0)

回复引用

#23楼 2013-05-06 11:41 Raylin

打错了是行合并怎么实现?

支持(0)反对(0)

回复引用

#24楼[楼主] 2013-05-06 13:46 陈希章

@Raylin

行合并和列合并都是可以的,默认就支持

支持(0)反对(0)

回复引用

#25楼 2013-05-06 15:10 Raylin

@陈希章

怎么选中单个格子呢?

支持(0)反对(0)

回复引用

#26楼[楼主] 2013-05-06 16:12 陈希章

@Raylin

选择格子是什么意思?Grid不支持选择格子的

支持(0)反对(0)

回复引用

#27楼 2013-05-06 17:21 Raylin

@陈希章

初学WPF,多谢陈老师指点!

支持(0)反对(0)

回复引用

#28楼[楼主] 2013-05-06 17:34 陈希章

@Raylin

不要紧,作为初学者可以认真看一下官方的入门材料

1. Introduction to WPF http://msdn.microsoft.com/en-us/library/aa970268.aspx

2. Getting Started (WPF) http://msdn.microsoft.com/en-us/library/ms742119.aspx

3. Walkthrough: Getting Started with WPF http://msdn.microsoft.com/en-us/library/ms752299.aspx

4. XAML Overview (WPF) http://msdn.microsoft.com/en-us/library/ms752059.aspx

支持(0)反对(0)

回复引用

#29楼 2013-09-22 11:09 柳佳同学

public class GridHelper

{

////A0B3C6

private static SolidColorBrush _BorderBrush = new SolidColorBrush(Colors.Black);

public static SolidColorBrush BorderBrush

{

get { return GridHelper._BorderBrush; }

set { GridHelper._BorderBrush = value; }

}

private static double _BorderThickness = 1;

public static double BorderThickness

{

get { return GridHelper._BorderThickness; }

set { GridHelper._BorderThickness = value; }

}

public static bool GetShowBorder(DependencyObject obj)

{

return (bool)obj.GetValue(ShowBorderProperty);

}

public static void SetShowBorder(DependencyObject obj, bool value)

{

obj.SetValue(ShowBorderProperty, value);

}

public static readonly DependencyProperty ShowBorderProperty =

DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridHelper), new PropertyMetadata(OnShowBorderChanged));

private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

var grid = d as Grid;

if ((bool)e.OldValue)

{

grid.Loaded -= (s, arg) => { };

}

if ((bool)e.NewValue)

{

grid.Loaded += (s, arg) =>

{

//确定行数和列数

var rows = grid.RowDefinitions.Count;

var columns = grid.ColumnDefinitions.Count;

var controls = grid.Children;

var count = controls.Count;

for (int i = 0; i < count; i++)

{

var item = controls[i] as FrameworkElement;

Border border = new Border();

border.BorderBrush = BorderBrush;

border.BorderThickness = new Thickness(0, 0, BorderThickness, BorderThickness);

var row = Grid.GetRow(item);

var column = Grid.GetColumn(item);

var rowspan = Grid.GetRowSpan(item);

var columnspan = Grid.GetColumnSpan(item);

Grid.SetRow(border, row);

Grid.SetColumn(border, column);

Grid.SetRowSpan(border, rowspan);

Grid.SetColumnSpan(border, columnspan);

grid.Children.Add(border);

}

//画最外面的边框

Border bo = new Border();

bo.BorderBrush = BorderBrush;

bo.BorderThickness = new Thickness(BorderThickness, BorderThickness, 0, 0);

bo.SetValue(Grid.ColumnProperty, 0);

bo.SetValue(Grid.RowProperty, 0);

bo.SetValue(Grid.ColumnSpanProperty, grid.ColumnDefinitions.Count);

bo.SetValue(Grid.RowSpanProperty, grid.RowDefinitions.Count);

bo.Tag = "autoBorder";

grid.Children.Add(bo);

};

}

}

}

支持(0)反对(0)

回复引用

#30楼 2013-10-24 09:27 Williame

不错,顶

为WPF和Silverlight的Grid添加边框线(zz),布布扣,bubuko.com

时间: 2024-10-05 23:09:12

为WPF和Silverlight的Grid添加边框线(zz)的相关文章

好玩的WPF第一弹:窗口抖动+边框阴影效果+倒计时显示文字

大家一进到博客就应该看到这张GIF了吧--好吧,今天不是星期一-- 那么就来一起做做这个效果啦!看完记得点赞哦~ 新建一个WPF项目 如果新建WPF项目应该不用我说了吧,在C#下面找找就好了. MainWindow.xaml 在初始的Window下添加如下属性: x:Name="mainWindow" WindowStartupLocation="CenterScreen" WindowState="Normal" WindowStyle=&qu

WPF,Silverlight与XAML读书笔记第十五 - 页间导航 页间数据传递

?说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘>的编排,对内容进行了总结并加入一些个人理解. 导航 有关导航的话题在介绍NavigationWindow与Page等元素时有提及.这篇文章将详细分析导航相关话题.同其它话题,针对WPF,Silverlight与WP 7,导航特性大致相似又有着些许不同.在介绍此特性时相同的特性将合在一起,每个框架独有的特性也将独立介绍并有明显标识. 导航的功能及目的就是从一个页面转向另一个页面,可能是前进亦或是后

WPF一步步实现完全无边框自定义Window(附源码)

原文:WPF一步步实现完全无边框自定义Window(附源码) 在我们设计一个软件的时候,有很多时候我们需要按照美工的设计来重新设计整个版面,这当然包括主窗体,因为WPF为我们提供了强大的模板的特性,这就为我们自定义各种空间提供了可能性,这篇博客主要用来介绍如何自定义自己的Window,在介绍整个写作思路之前,我们来看看最终的效果. 图一 自定义窗体主界面 这里面的核心就是重写Window的Template,针对整个开发过程中出现的问题我们再来一步步去剖析,首先要看看我们定义好的样式 <Resou

Simple Path Data Resources that I Add to Every WPF and Silverlight Project

Here’s a little time saver. I sort of have a routine that I go through when I create a new WPF project. One of those things is to create a resource dictionary (I’m down to one on most projects now, but more on that later) that includes some common st

浅析WCF与WebService、WPF与Silverlight 区别

由于在<Windows服务调用Quartz.net 实现消息调度>中,涉及到ASP.NET Web Service //WebServiceSoapClient client = new WebServiceSoapClient(new BasicHttpBinding(), new EndpointAddress(URL));//client.Shake(); 效果始终不是太好,故Google查之,此文做为平时积累. 一.ASP.NET Web Service Web Service:严格来

Grid画边框

public class GridHelper { //请注意:可以通过propa这个快捷方式生成下面三段代码 public static bool GetShowBorder(DependencyObject obj) { return (bool)obj.GetValue(ShowBorderProperty); } public static void SetShowBorder(DependencyObject obj, bool value) { obj.SetValue(ShowBo

[WPF 如何] 如何向 ComboBox 添加一个空白选项

原文:[WPF 如何] 如何向 ComboBox 添加一个空白选项 看到这个问题,你可能会蔑视一笑 : 这也能成文章? 确实,你只需要在 ItemsSource 的0位置上插入一个空白的项就是了,如: 1 this.Accounts = rep.All.OrderBy(a => a.Account).Select(a => a.Account).ToList(); 2 this.Accounts.Insert(0, ""); 1 <ComboBox Grid.Colu

WPF开发为按钮提供添加,删除和重新排列ListBox内容的功能

原文:WPF开发为按钮提供添加,删除和重新排列ListBox内容的功能 介绍 我有一种情况,我希望能够将项目添加到列表中,并在列表中移动项目,这似乎是使用a的最简单方法ListBox.我立刻想到了如何以通用的方式做到这一点,然后,也许,可以使用行为来做到这一点.这似乎是一个非常有用的想法.我决定以一种简单的方式为我正在开发的应用程序做这件事,但我想我会创建一个演示项目来探索这个想法.这是结果. 概观 该行为实际上有四个独立的部分,可以在一个类中执行不同的功能: 添加项目 将所选项目向上移动一个位

企业级架构 MVVM 模式指南 (WPF 和 Silverlight 实现) 译(2)

本书包含的章节内容 第一章:表现模式,以一个例子呈献给读者表现模式的发展历程,我们会用包括MVC和MVP在内的各种方式实现一个收费项目的例子.沿此方向,我们会发现每一种模式的问题所在,这也是触发设计模式发展的原因.本章还会说明如果应用不当,MVC和MVP这些依赖.Net事件的表现模式是怎么导致内存泄漏的.本章会谈论各种表现模式的优缺点,并且留给读者自我思考的问题,如为什么用MVVM设计模式来代替MVP或是MVC.第二章:介绍MVVM,包括使MVVM魅力四射的WPF和Silverlight的各种特