天天看點

【WP7進階】——分享一個可供切換狀态的ListBox元件

編寫Asp.net的同學,經常會遇到一個Repeater 或者一個GridView ,當使用者點選編輯狀态時我們的清單元件會自動跳轉到可選擇(可供删除、編輯、選擇等)狀态。這時候一般的做法都會在元件的前方自動生成一系列複選框“CheckBox”,需要删除/選擇哪行時隻要在前方的複選框勾一下,便可以得到該行的資料或者行ID等。

  上面的做法是一個比較典型的Web做法,那麼在WP7 裡面要實作這樣的效果如何實作呢?有些同學就會說了,那簡單使用ListBox 在它的資料模闆裡面添加一個CheckBox不就完事了嗎?是的,這樣是一種做法,但帶來的問題是你得去控制他選中哪行并且得到哪行的ID,并且在WP7 有限的螢幕中這種做法比較不妥,當使用者想做選擇時,我們才讓對應的行有可供選擇的狀态才更佳。而這種做法在傳統的WP7控件中,是沒有的。因為我們必須時時去控制它的複選框顯示或者隐藏,但在這裡我推薦大家一個元件,自帶CheckBOx并且預設有兩種狀态,一種為普通狀态即呈現資料顯示給使用者,如下圖:

另外一種狀态為可選擇狀态,即使用者可以對相應的行做删除等操作,如下圖:

下面給出該元件的詳細用法:

做過.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 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)

代碼跟上邊的代碼差不多,這裡多了調用加載資料的方法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)

        /// 建構應用程式條

        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);

            #region --取消--

            this.applicationBarIconButtonCancel = new ApplicationBarIconButton(new Uri("/content/ApplicationBar.Cancel.png",UriKind.Relative));

            this.applicationBarIconButtonCancel.Text = "取消";

            this.applicationBarIconButtonCancel.Click += new EventHandler(applicationBarIconButtonCancel_Click);

            this.applicationBarDeleteOrCancel.Buttons.Add(this.applicationBarIconButtonDelete);

            this.applicationBarDeleteOrCancel.Buttons.Add(this.applicationBarIconButtonCancel);

            this.applicationBarDeleteOrCancel.IsMenuEnabled = true;

            this.applicationBarDeleteOrCancel.IsVisible = true;

        /// listBox 為可選擇狀态

        private void SwitchToChooseState()

            this.listBoxWithBoxes.IsInChooseState = true;

            this.ApplicationBar = this.applicationBarDeleteOrCancel;

        /// listBox 為普通狀态

        private void SwitchToNormalState()

            this.listBoxWithBoxes.IsInChooseState = false;

        /// 取消操作

        /// <param name="sender"></param>

        /// <param name="e"></param>

        void applicationBarIconButtonCancel_Click(object sender, EventArgs e)

            SwitchToNormalState();

        /// 删除操作

        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();

        /// 選擇操作

        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:該效果隻運用于沒有運作即可檢視效果,運作後将會忽略。

怎麼樣,該元件不錯吧,大家下載下傳後試試吧。

源碼下載下傳:

<a href="http://files.cnblogs.com/TerryBlog/ListBoxWithCheckBox.rar" target="_blank">ListBoxWithCheckBox Demo</a>

 本文轉自 terry_龍 51CTO部落格,原文連結:http://blog.51cto.com/terryblog/497004,如需轉載請自行聯系原作者