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

  编写Asp.net的同学,经常会遇到一个Repeater 或者一个GridView ,当用户点击编辑状态时我们的列表组件会自动跳转到可选择(可供删除、编辑、选择等)状态。这时候一般的做法都会在组件的前方自动生成一系列复选框“CheckBox”,需要删除/选择哪行时只要在前方的复选框勾一下,便可以得到该行的数据或者行ID等。
  上面的做法是一个比较典型的Web做法,那么在WP7 里面要实现这样的效果如何实现呢?有些同学就会说了,那简单使用ListBox 在它的数据模板里面添加一个CheckBox不就完事了吗?是的,这样是一种做法,但带来的问题是你得去控制他选中哪行并且得到哪行的ID,并且在WP7 有限的屏幕中这种做法比较不妥,当用户想做选择时,我们才让对应的行有可供选择的状态才更佳。而这种做法在传统的WP7控件中,是没有的。因为我们必须时时去控制它的复选框显示或者隐藏,但在这里我推荐大家一个组件,自带CheckBOx并且默认有两种状态,一种为普通状态即呈现数据显示给用户,如下图:

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


该组件的下载地址为:WindowsPhoneListBoxWithCheckBoxesControl

下面给出该组件的详细用法:
做过.Net 开发的对于如何使该组件的应该很清楚,这里将跳过此步骤。
  如上图,该组件编写的XAML代码为如下:


<myistBoxWithCheckBoxes 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>
</myistBoxWithCheckBoxes>



如上代码的数据模板,并未出现有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 做数据,代码如下: <viewModelsistModel
       
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      
        xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModels
    ="clr-namespaceistBoxWithCheckBox.ViewModel">
    <viewModelsistModel.SimpleModels>
    <viewModels:SimpleModel Name="测试第一项" Description="这是测试的第一个节点"
    />
    <viewModels:SimpleModel Name="测试第二项" Description="这是测试的第二个节点"
    />
    </viewModelsistModel.SimpleModels>
    </viewModelsistModel>


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


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

怎么样,该组件不错吧,大家下载后试试吧。
源码下载:
ListBoxWithCheckBox Demo

 

 

 

 

 

原贴地址:http://bbs.silverlightchina.net/forum.php?mod=viewthread&tid=3707

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值