【WP7进阶】——分享一个可供切换状态的ListBox组件

简介:

编写Asp.net的同学,经常会遇到一个Repeater 或者一个GridView ,当用户点击编辑状态时我们的列表组件会自动跳转到可选择(可供删除、编辑、选择等)状态。这时候一般的做法都会在组件的前方自动生成一系列复选框“CheckBox”,需要删除/选择哪行时只要在前方的复选框勾一下,便可以得到该行的数据或者行ID等。

  上面的做法是一个比较典型的Web做法,那么在WP7 里面要实现这样的效果如何实现呢?有些同学就会说了,那简单使用ListBox 在它的数据模板里面添加一个CheckBox不就完事了吗?是的,这样是一种做法,但带来的问题是你得去控制他选中哪行并且得到哪行的ID,并且在WP7 有限的屏幕中这种做法比较不妥,当用户想做选择时,我们才让对应的行有可供选择的状态才更佳。而这种做法在传统的WP7控件中,是没有的。因为我们必须时时去控制它的复选框显示或者隐藏,但在这里我推荐大家一个组件,自带CheckBOx并且默认有两种状态,一种为普通状态即呈现数据显示给用户,如下图:

另外一种状态为可选择状态,即用户可以对相应的行做删除等操作,如下图:

 

该组件的下载地址为:WindowsPhoneListBoxWithCheckBoxesControl

 

下面给出该组件的详细用法:

做过.Net 开发的对于如何使该组件的应该很清楚,这里将跳过此步骤。

  如上图,该组件编写的XAML代码为如下:

 

  < my:ListBoxWithCheckBoxes  Name ="listBoxWithBoxes"  Margin ="0,0,0,0"  ItemsSource =" {Binding SimpleModels} " >
                
< ListBox.ItemTemplate >
                    
< DataTemplate >
                        
< StackPanel  Orientation ="Horizontal"  Margin ="0,0,0,20" >
                            
< Rectangle  Height ="100"  Width ="100"  Fill ="#FFE5001b"  Margin ="12,0,9,0" />
                            
< StackPanel >
                                
< TextBlock  Text =" {Binding Name} "  TextWrapping ="Wrap"  Style =" {StaticResource PhoneTextLargeStyle} " />
                                
< TextBlock  Text =" {Binding Description} "  TextWrapping ="Wrap"  Margin ="12,-6,12,0"  Style =" {StaticResource PhoneTextSubtleStyle} " />
                            
</ StackPanel >
                        
</ StackPanel >
                    
</ DataTemplate >
                
</ ListBox.ItemTemplate >
  
</ my:ListBoxWithCheckBoxes >

 

 

如上代码的数据模板,并未出现有CheckBox 控件,因为该组件己经将CheckBox控件整合在里面的选择状态中了。下面是具体如何为该组件添加数据。

首先该组件对应的行有标题和描述,这个在上面XAML代码中的数据模板可以看得出,查看该组件的ItemSource ,一起来看看它的代码是如何编写的:

 

public   class  SimpleModel : INotifyPropertyChanged
    {
        
protected   string  itsName;
        
protected   string  itsDescription;

        
public   event  PropertyChangedEventHandler PropertyChanged;

        
public   string  Name 
        {
            
get  {  return   this .itsName; }
            
set  {  this .itsName  =  value; NotifyPropertyChanged( " Name " ); }
        }


        
public   string  Description
        {
            
get  {  return   this .itsDescription; }
            
set  {  this .itsDescription  =  value; NotifyPropertyChanged( " Description " ); }
        }



        
protected   void  NotifyPropertyChanged( string  thePropertyName) 
        {
            
if  ( this .PropertyChanged != null )
            {
                
this .PropertyChanged( this new  PropertyChangedEventArgs(thePropertyName));
            }
        }

    }

 

 

代码比较简单,封装了两个属性分别为他们注册PropertyChanged 事件响应数据变化。

 

而这个MODEL的数据来源于如下代码:

 

  public   class  ListModel : INotifyPropertyChanged
    {
        
public   event  PropertyChangedEventHandler PropertyChanged;

        
public  ObservableCollection < SimpleModel >  SimpleModels {  get private   set ; }



        
public   bool  IsDataLoaded {  get private   set ; }

        
public  ListModel() 
        {
            
this .SimpleModels  =   new  ObservableCollection < SimpleModel > ();
        }


        
///   <summary>
        
///  加载数据
        
///   </summary>
         public   void  LoadData() 
        {
            
for  ( int  i  =   1 ; i  <   1000 ; i ++ )
            {
                
this .SimpleModels.Add( new  SimpleModel() { Name  =   " "   +  i  +   " " , Description  =   " 这是第 "   +  i  +   " 项数据 "  });
            }
            
this .IsDataLoaded  =   true ;
        }


        
protected   void  NotifyPropertyChanged( string  thePropertyName)
        {
            
if  ( this .PropertyChanged != null )
            {
                
this .PropertyChanged( this new  PropertyChangedEventArgs(thePropertyName));
            }
        }

    }

 

 

代码跟上边的代码差不多,这里多了调用加载数据的方法LoadData()为上面的每个Model赋值。而加载代码首先为其添加一个全局属性:

 

  public   static  ListBoxWithCheckBox.ViewModel.ListModel viewModel  =   null ;

        
// 获取数据
         public   static  ViewModel.ListModel ViewModel 
        {
            
get  {
                
if  (viewModel == null )
                {
                    viewModel 
=   new  ViewModel.ListModel();
                }
                
return  viewModel;
            }
        }

 

 

转到MainPage的code behind 代码里面,在构造函数里面为DataContext 赋值,这里赋值的话上下文即可得到数据源,代码如下:

  DataContext = App.ViewModel;

 

当应用程序导航进来时,调用加载全局属性去执行抓取数据的方法,代码如下:

 

   protected   override   void  OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            
if  ( ! App.ViewModel.IsDataLoaded)
            {
                App.ViewModel.LoadData();
            }
            
base .OnNavigatedTo(e);
        }

 

 

 

最后的运行效果,我们选择第1 、2条数据做为欲删除的对象,然后删除看有啥变化?

 

点击删除后的效果:

 

mainPage 的code behind 完整代码如下:

完整代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;
using  Microsoft.Phone.Controls;
using  Microsoft.Phone.Shell;
using  ListBoxWithCheckBox.ViewModel;

namespace  ListBoxWithCheckBox
{
    
public   partial   class  MainPage : PhoneApplicationPage
    {

        
private  ApplicationBar applicationBarChoose;
        
private  ApplicationBarIconButton applicationBarIconButtonChoose;

        
private  ApplicationBar applicationBarDeleteOrCancel;
        
private  ApplicationBarIconButton applicationBarIconButtonDelete;
        
private  ApplicationBarIconButton applicationBarIconButtonCancel;

        
//  Constructor
         public  MainPage()
        {
            InitializeComponent();
            ConstructApplicationBar();
            DataContext 
=  App.ViewModel;
            
this .Loaded  +=   new  RoutedEventHandler(MainPage_Loaded);
        }

        
void  MainPage_Loaded( object  sender, RoutedEventArgs e)
        {
           
        }

        
protected   override   void  OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            
if  ( ! App.ViewModel.IsDataLoaded)
            {
                App.ViewModel.LoadData();
            }
            
base .OnNavigatedTo(e);
        }


        
///   <summary>
        
///  构建应用程序条
        
///   </summary>
         private   void  ConstructApplicationBar()
        {
            
#region --应用程序条“选择”菜单--
            
this .applicationBarChoose  =   new  ApplicationBar();
            
this .applicationBarIconButtonChoose  =   new  ApplicationBarIconButton( new  Uri( " /content/ApplicationBar.Choose.png " ,UriKind.Relative));
            
this .applicationBarIconButtonChoose.Text  =   " 选择 " ;
            
this .applicationBarIconButtonChoose.Click  +=   new  EventHandler(applicationBarIconButtonChoose_Click);
            
this .applicationBarChoose.Buttons.Add( this .applicationBarIconButtonChoose);
            
this .applicationBarChoose.IsMenuEnabled  =   true ;
            
this .applicationBarChoose.IsVisible  =   true ;
            
this .ApplicationBar  =   this .applicationBarChoose;
            
#endregion


            
this .applicationBarDeleteOrCancel  =   new  ApplicationBar();
            
#region  --删除--
            
this .applicationBarIconButtonDelete  =   new  ApplicationBarIconButton( new  Uri( " /content/ApplicationBar.Delete.png " ,UriKind.Relative));
            
this .applicationBarIconButtonDelete.Text  =   " 删除 " ;
            
this .applicationBarIconButtonDelete.Click  +=   new  EventHandler(applicationBarIconButtonDelete_Click);
            
#endregion


            
#region  --取消--
            
this .applicationBarIconButtonCancel  =   new  ApplicationBarIconButton( new  Uri( " /content/ApplicationBar.Cancel.png " ,UriKind.Relative));
            
this .applicationBarIconButtonCancel.Text  =   " 取消 " ;
            
this .applicationBarIconButtonCancel.Click  +=   new  EventHandler(applicationBarIconButtonCancel_Click);
            
#endregion

            
this .applicationBarDeleteOrCancel.Buttons.Add( this .applicationBarIconButtonDelete);
            
this .applicationBarDeleteOrCancel.Buttons.Add( this .applicationBarIconButtonCancel);
            
this .applicationBarDeleteOrCancel.IsMenuEnabled  =   true ;
            
this .applicationBarDeleteOrCancel.IsVisible  =   true ;

        }

        
///   <summary>
        
///  listBox 为可选择状态
        
///   </summary>
         private   void  SwitchToChooseState()
        {
            
this .listBoxWithBoxes.IsInChooseState  =   true ;
            
this .ApplicationBar  =   this .applicationBarDeleteOrCancel;
        }

        
///   <summary>
        
///  listBox 为普通状态
        
///   </summary>
         private   void  SwitchToNormalState()
        {
            
this .listBoxWithBoxes.IsInChooseState  =   false ;
            
this .ApplicationBar  =   this .applicationBarChoose;
        }


        
///   <summary>
        
///  取消操作
        
///   </summary>
        
///   <param name="sender"></param>
        
///   <param name="e"></param>
         void  applicationBarIconButtonCancel_Click( object  sender, EventArgs e)
        {
            SwitchToNormalState();
        }

        
///   <summary>
        
///  删除操作
        
///   </summary>
        
///   <param name="sender"></param>
        
///   <param name="e"></param>
         void  applicationBarIconButtonDelete_Click( object  sender, EventArgs e)
        {
            
if  (MessageBox.Show( " 你确定要删除选中项吗? " , " 提示 " ,MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                
foreach  (SimpleModel item  in   this .listBoxWithBoxes.SelectedItems)
                {
                    App.ViewModel.SimpleModels.Remove(item);
                }
                SwitchToNormalState();
            }
        }

        
///   <summary>
        
///  选择操作
        
///   </summary>
        
///   <param name="sender"></param>
        
///   <param name="e"></param>
         void  applicationBarIconButtonChoose_Click( object  sender, EventArgs e)
        {
            SwitchToChooseState();
        }
    }
}

 

 

这里推荐一个小技巧,当我们编写动态数据时,又不想运行即想从代码IDE看到运行效果,类似于这样:

 

这个效果还是要借用PhoneApplicationPage 的DataContext属性,具体如下编写代码:

  • 编写一个数据xaml命名为:ViewModelSampleData.xaml 文件,该文件负责为SimpleModels 做数据,代码如下:
    < viewModels:ListModel 
        
    xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        
        xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModels
    ="clr-namespace:ListBoxWithCheckBox.ViewModel" >

        
    < viewModels:ListModel.SimpleModels >
            
    < viewModels:SimpleModel  Name ="测试第一项"  Description ="这是测试的第一个节点"   />
            
    < viewModels:SimpleModel  Name ="测试第二项"  Description ="这是测试的第二个节点"   />
        
    </ viewModels:ListModel.SimpleModels >
        
    </ viewModels:ListModel >

     

  • 在MainPage文件的XAML界面为DataContext赋值,代码如下:
        d:DataContext="{d:DesignData ViewModelSampleData.xaml}"

     

Tip:该效果只运用于没有运行即可查看效果,运行后将会忽略。

 

怎么样,该组件不错吧,大家下载后试试吧。

源码下载:

ListBoxWithCheckBox Demo






 本文转自 terry_龙 51CTO博客,原文链接:http://blog.51cto.com/terryblog/497004,如需转载请自行联系原作者

相关文章
|
5月前
|
小程序 JavaScript 前端开发
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
160 0
|
Python
PyQt5-基本控件| 主窗口的类型、创建以及代码如何实现?
PyQt5-基本控件| 主窗口的类型、创建以及代码如何实现?
76 1
|
前端开发
前端学习笔记202305学习笔记第二十二天-新增修改弹框复用1
前端学习笔记202305学习笔记第二十二天-新增修改弹框复用1
41 0
|
前端开发
前端学习笔记202305学习笔记第二十二天-新增修改弹框复用5
前端学习笔记202305学习笔记第二十二天-新增修改弹框复用5
59 0
|
前端开发
前端学习笔记202305学习笔记第二十二天-新增修改弹框复用3
前端学习笔记202305学习笔记第二十二天-新增修改弹框复用3
64 0
iframe框架学习笔记---点击切换路径
iframe框架学习笔记---点击切换路径
88 0
|
数据安全/隐私保护
uniapp动态切换显示不同内容组件
通过点击注册或是登录按钮切换不同的组件.默认显示登陆界面,登录字样加粗显示,登录页面显示手机号密码登录.
uniapp动态切换显示不同内容组件
SwiftUI—使用TabView包含和切换多个页面
SwiftUI—使用TabView包含和切换多个页面
943 0
SwiftUI—使用TabView包含和切换多个页面
|
前端开发 程序员
Qt-QML-ComboBox-自定义,实现状态表示,内容可以动态正价,使用ListModel
Qt-QML-ComboBox-自定义,实现状态表示,内容可以动态正价,使用ListModel
827 0
Qt-QML-ComboBox-自定义,实现状态表示,内容可以动态正价,使用ListModel