大树下好乘凉

导航

自定义WPF常用控件(1)--页码控件

 

  页码显示和翻页控件是使用相当广泛的一种控件,几乎是随处可见。

  总结起来,此类控件,一般都具有页码显示、前跳、后跳、快速跳转等功能,某些控件可能包含页码特殊设置,当前页/总页数显示等。于是乎我们就有了自定义此类控件的思路。

一、控件预览

  先把成品给大家看看吧:

控件外观

  这个控件功能倒是有了,但是挺难看的啊?别急,配合依赖属性和属性回调我们可以实现如其他内置WPF控件一样的样式设置功能,并且在VS的WPF/Silverlight设计器中实时显示。效果:

设置了样式的控件

  如果嫌显示太长,不想要显示这么多内容,也可以进行设置,将指定的项隐藏起来,这些我是使用普通属性进行设置。下图是隐藏了总页数,和每页条数设置项的效果:

隐藏了部分显示项

  下面说说这个控件的具体实现。实际上控件的设计很简单,将Grid分成若干份,隔一格放个控件就行了。

控件设计样式

二、控件逻辑

  之后便是控件的内置逻辑关系,我设定的关系是以下几种:

1、设置当前页时,不能小于0,也不能大于总页数。

2、设置总页数时,不能小于0,也不能小于当前页。

3、如果当前页为0或者1,则“上页”按钮不可用,如果当前页等于总页数,则“下页”按钮不可用。

4、如果跳转页输入框输入了不合法的数,则“跳转”页按钮不可用;如果输入的数等于当前页或者等于总页数,则“跳转”按钮也不可用。

5、设置每页显示条数时,不能小于1,并且实时更新总页数;若重新设置每页条数后,之前的当前页页数大于新的总页数,则将当前页置1,否则保持现在的当前页页码,并加载对应页的数据。

6、若设置数据源总条数,则依据上面的规则,自动计算所有数值。

7、依据1、2规则可知:

(1)若控件是处于初始状态,则必须先于当前页设置总页数;

(2)若控件需要设为初始值,则必须在设置总页数为0之前,将当前页置为0。

我将以上规则,包含在了属性的set中。 属性设置使用了类Category,对控件属性进行分组,并使用了Description对控件进行描述。这样,在VS实时设计器中,就可以看到分组后的属性,并且有ToolTip描述,不至于所有的属性都被放到“通用”标签里面。

 

属性查看器

设置当前页:

 

View Code
        /// <summary>
        
/// 获取或设置当前页数
        
/// </summary>
        [Category("页码"), Description("当前显示的页码")]
        
public int PageNow
        {
            
get { return m_PageNow; }
            
set
            {
                
if (value >= 0)
                {
                    
if (m_PageTotal != -1)
                    {
                        
if (value <= m_PageTotal)
                        {
                            TxbPageNow.Text 
= value.ToString();
                            m_PageNow 
= value;
                            
//根据当前页设置 "上页" 按钮状态
                            if (m_PageNow > 1)
                                BtnPrev.IsEnabled 
= true;
                            
else
                                BtnPrev.IsEnabled 
= false;

                            
//根据当前页和总页数设置 "后页" 按钮状态
                            if (m_PageNow < m_PageTotal)
                                BtnNext.IsEnabled 
= true;
                            
else
                                BtnNext.IsEnabled 
= false;
                        }
                        
else
                            MessageBox.Show(
"当前页不能大于总页数""属性设置", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    
else
                    {
                        TxbPageNow.Text 
= value.ToString();
                        m_PageNow 
= value;
                    }
                }
                
else
                    PageNow 
= 0;
            }
        }

 

设置总页数:

 

View Code
        /// <summary>
        
/// 获取或设置总页数
        
/// </summary>
        [Category("页码"), Description("数据总页数")]
        
public int PageTotal
        {
            
get { return m_PageTotal; }
            
private set
            {
                
if (value >= 0)
                {
                    
if (m_PageNow != -1)
                    {
                        
if (value >= m_PageNow)
                        {
                            m_PageTotal 
= value;
                            TxbPageTotal.Text 
= value.ToString();
                            
//根据当前页和总页数设置 "后页" 按钮状态
                            if (m_PageNow < m_PageTotal)
                                BtnNext.IsEnabled 
= true;
                            
else
                                BtnNext.IsEnabled 
= false;
                        }
                        
else
                            MessageBox.Show(
"总页数不能小于当前页""属性设置", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    
else
                    {
                        m_PageTotal 
= value;
                        TxbPageTotal.Text 
= value.ToString();
                    }
                }
                
else
                    PageTotal 
= 0;
            }
        }

 

设置要跳转的页面:

 

View Code
        /// <summary>
        
/// 获取或设置要跳转的页面
        
/// </summary>
        [Category("页码"), Description("将要跳转的页码")]
        
public int PageToJump
        {
            
get { return m_PageToJump; }
            
set
            {
                
if (value >= 0)
                {
                    
if (m_PageTotal != -1)
                    {
                        
if (value <= m_PageTotal)
                        {
                            m_PageToJump 
= value;
                            TxbxPage.Text 
= value.ToString();
                            
//根据总页数,设置 "跳转" 按钮状态
                            if (m_PageToJump > 0 &&
                                        m_PageToJump 
<= m_PageTotal &&
                                        m_PageToJump 
!= m_PageNow)
                            {
                                BtnJump.IsEnabled 
= true;
                            }
                            
else
                                BtnJump.IsEnabled 
= false;
                        }
                        
//如果输入的页数超出总页数,则禁用跳转按钮
                        else
                            BtnJump.IsEnabled 
= false;
                    }
                    
else
                    {
                        m_PageToJump 
= value;
                        TxbxPage.Text 
= value.ToString();
                    }
                }
                
//输入的数字小于0,禁用跳转按钮
                else
                    PageToJump 
= 0;
            }
        }

 

设置每页显示条数:

 

View Code
        /// <summary>
        
/// 获取或设置每页的条数
        
/// </summary>
        [Category("页码"), Description("每页显示的条数")]
        
public int PageSize
        {
            
get { return m_PageSize; }
            
set
            {
                
if (value < 1)
                {
                    MessageBox.Show(
"每页条数不能小于1""属性设置", MessageBoxButton.OK, MessageBoxImage.Error);
                    
return;
                }
                m_PageSize 
= value;
                
if (m_SourceCount == 0)
                    PageTotal 
= PageNow = 0;
                
else
                {
                    
int PageNowTemp = m_PageNow;
                    PageNow 
= 0;
                    PageTotal 
= (int)Math.Ceiling((double)m_SourceCount / (double)m_PageSize);

                    
if (PageNowTemp <= m_PageTotal && PageNowTemp > 0)
                        PageNow 
= PageNowTemp;
                    
else
                        PageNow 
= 1;
                }
                ComboxPageSize.Text 
= m_PageSize.ToString();
            }
        }

 

设置数据源条数:

 

View Code
        /// <summary>
        
/// 获取或设置数据源条数
        
/// </summary>
        [Category("页码"), Description("数据源的总条数")]
        
public int SourceCount
        {
            
get { return m_SourceCount; }
            
set
            {
                
if (value <= 0)
                    m_SourceCount 
= PageTotal = PageNow = 0;
                
else
                {
                    m_SourceCount 
= value;
                    
int PageNowTemp = m_PageNow;
                    PageNow 
= 0;
                    PageTotal 
= (int)Math.Ceiling((double)m_SourceCount / (double)m_PageSize);

                    
if (PageNowTemp <= m_PageTotal && PageNowTemp > 0)
                        PageNow 
= PageNowTemp;
                    
else
                        PageNow 
= 1;
                }
                TxbSourceCount.Text 
= m_SourceCount.ToString();
            }
        }

 

三、控件事件

  目前控件封装的事件有四个:“前页”按钮点击事件,“后页”按钮点击事件、跳转按钮点击事件、下拉框页码文本改变事件。使用的EventHandler类,可以减少声明委托的代码。

以“前页”按钮为例:

事件声明:

 

View Code
        /// <summary>
        
/// 返回上一个的事件
        
/// </summary>
        public event EventHandler<EventArgs> GoPrev;

 

事件实现中,仅改变当前页数字,具体事情,由控件使用者来实现:

 

View Code
        /// <summary>
        
/// 点击"上页"按钮的事件
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void BtnPrev_Click(object sender, RoutedEventArgs e)
        {
            PageNow
--;
            
if (GoPrev != null)
                GoPrev(sender, e);
        }

 

其他的事件原理相同,可以看源码

 

四、控件样式

  控件样式也是很重要的,做WPF可不能忘了这个,但是我们要把样式设置暴露给控件使用者,还得能够实时改变,借助依赖属性和属性回调可以轻松实现。

样式的设置我分为了几种类型:

1、 文本提示样式,也就是“当前页”,“总页数”,“页条数”等文本的样式。

2、 文本样式,就是输入跳转页的TextBox的样式

3、 下拉框头样式

4、 下拉框Item样式

5、 按钮样式

 

由于代码几乎相同,我就介绍下文本提示样式。

首先是依赖属性注册:

 

View Code
        /// <summary>
        
/// 提示文本样式
        
/// </summary>
        private static readonly DependencyProperty TipTextStyleProperty =
            DependencyProperty.Register(
            
"TipTextStyle",
            
typeof(Style),
            
typeof(BottomBtns),
            
new FrameworkPropertyMetadata(new PropertyChangedCallback(TipTextStyleChangedCallback)));

 

然后是编写对应公有属性

 

View Code
        /// <summary>
        
/// 获取或设置文本样式
        
/// </summary>
        [Category("外观"), Description("显示文本样式")]
        
public Style TextStyle
        {
            
get { return (Style)GetValue(TextStyleProperty); }
            
set { SetValue(TextStyleProperty, value); }
        }

 

再就是回调,VS的WPF/Silverlight设计器要调用此方法来实时显示效果

 

View Code
        /// <summary>
        
/// 文本提示样式属性改变回调
        
/// </summary>
        
/// <param name="d"></param>
        
/// <param name="e"></param>
        private static void TipTextStyleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BottomBtns BB 
= ((BottomBtns)d);
            BB.TxbPageNow.Style 
=
                    BB.TxbPageTotal.Style 
=
                    BB.TxbSlashTip.Style 
=
                    BB.TxbPageNowTip.Style 
=
                    BB.TxbSourceCountTip.Style 
=
                    BB.TxbSourceCount.Style 
=
                    BB.TxbPageSizeTip.Style 
= BB.TipTextStyle;
        }

 

 

完整源代码下载: /Files/chenl861004/WPF控件/ButtomBtns.rar

posted on 2011-05-10 15:06  大树下好乘凉  阅读(1448)  评论(0编辑  收藏  举报