zoukankan      html  css  js  c++  java
  • MVVM体验记之DataGrid绑定

        知道MVVM这个词已经很久,但是一直没有去认识一下它,恰好这几天正在做点Silverlight的东西玩,顺便就也见识一下MVVM。

        准备工作:

    1、Silverlight 4包括SDK 及 Silverlight 4 Toolkit April 2010

    2、创建实体类(将在后面的DEMO中使用)People.cs:

        public class People
        {
            public string Name { get; set; }
    
            public int Age { get; set; }
        }

    3、创建实体类相应View视图PeopleView.xaml:

        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Row="0" Grid.Column="0" Text="姓名:" />
            <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}" />
            <TextBlock Grid.Row="1" Grid.Column="0" Text="年龄:" />
            <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Age}" />
        </Grid>

    4、创建ViewModel(PropertyChangedBase来自这里),使它实现INotifyPropertyChanged接口:

        public class PeopleViewModel : PropertyChangedBase
        {
            public PeopleViewModel()
            {
                Peoples = new ObservableCollection<People>();
                for (int i = 10; i < 30; i++)
                {
                    Peoples.Add(new People { Name = "test" + i.ToString(), Age = i });
                }
            }
    
            private People selectedPeople;
    
            public People SelectedPeople
            {
                get { return selectedPeople; }
                set
                {
                    selectedPeople = value;
                    this.NotifyPropertyChanged(p => p.SelectedPeople);
                }
            }
    
            public ObservableCollection<People> Peoples { get; set; }
    
        }

    接下来开始DEMO

    一、绑定DataGrid当前选中的行SelectedItem

    创建DEMO1页面,Xaml代码为:

    <UserControl x:Class="LWME.MVVMExperience.Views.Demo1"
        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"
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
        xmlns:v="clr-namespace:LWME.MVVMExperience.Views"
        xmlns:vm="clr-namespace:LWME.MVVMExperience.ViewModel"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
        <UserControl.Resources>
            <vm:PeopleViewModel x:Key="vm1" />
        </UserControl.Resources>
        <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource vm1}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="400" />
            </Grid.ColumnDefinitions>
            <sdk:DataGrid Grid.Column="0" ItemsSource="{Binding Peoples}" SelectedItem="{Binding SelectedPeople, Mode=TwoWay}" />
            <StackPanel Grid.Column="1" HorizontalAlignment="Center">
                <TextBlock Text="当前选中:" />
                <v:PeopleView DataContext="{Binding SelectedPeople}" />
            </StackPanel>
        </Grid>
    </UserControl>

    运行它,可以看到选择DataGrid某一行的时候,右边相应的详细信息也跟着变了,但这里并没有写任何代码,是不是很神奇呢?

    二、绑定选择的多行SelectedItems

        上面由于SelectedItem同时有get、set访问器,所以支持直接绑定。但是SelectedItems是不支持set访问器的,所以无法直接绑定。有人提到使用Command来解决这一问题,现在便用一下他的方法吧:

        首先,实现ICommand接口:

        public class RelayCommand<T> : ICommand
        {
            /// <summary>
            /// Occurs when changes occur that affect whether the command should execute.
            /// </summary>
            public event EventHandler CanExecuteChanged;
    
            Predicate<T> canExecute;
            Action<T> executeAction;
            bool canExecuteCache;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="RelayCommand"/> class.
            /// </summary>
            /// <param name="executeAction">The execute action.</param>
            public RelayCommand(Action<T> executeAction) : this(executeAction, null) { }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="RelayCommand"/> class.
            /// </summary>
            /// <param name="executeAction">The execute action.</param>
            /// <param name="canExecute">The can execute.</param>
            public RelayCommand(Action<T> executeAction,
                                   Predicate<T> canExecute)
            {
                this.executeAction = executeAction;
                this.canExecute = canExecute;
            }
    
            #region ICommand Members
            /// <summary>
            /// Defines the method that determines whether the command 
            /// can execute in its current state.
            /// </summary>
            /// <param name="parameter">
            /// Data used by the command. 
            /// If the command does not require data to be passed,
            /// this object can be set to null.
            /// </param>
            /// <returns>
            /// true if this command can be executed; otherwise, false.
            /// </returns>
            public bool CanExecute(object parameter)
            {
                if (canExecute == null)
                    return true;
    
                bool tempCanExecute = canExecute((T)parameter);
    
                if (canExecuteCache != tempCanExecute)
                {
                    canExecuteCache = tempCanExecute;
                    if (CanExecuteChanged != null)
                    {
                        CanExecuteChanged(this, EventArgs.Empty);
                    }
                }
    
                return canExecuteCache;
            }
    
            /// <summary>
            /// Defines the method to be called when the command is invoked.
            /// </summary>
            /// <param name="parameter">
            /// Data used by the command. 
            /// If the command does not require data to be passed, 
            /// this object can be set to null.
            /// </param>
            public void Execute(object parameter)
            {
                executeAction((T)parameter);
            }
            #endregion
        }

      接下来,修改PeopleViewModel,定义一个Command属性以绑定到DataGrid的SelectionChange事件,同时添加其他需要用于多选的属性:

        public class PeopleViewModel : PropertyChangedBase
        {
            public PeopleViewModel()
            {
                Peoples = new ObservableCollection<People>();
                for (int i = 10; i < 30; i++)
                {
                    Peoples.Add(new People { Name = "test" + i.ToString(), Age = i });
                }
    
                SelectionChangedCommand = new RelayCommand<IList>(SelectionChanged);
            }
    
            private People selectedPeople;
    
            public People SelectedPeople
            {
                get { return selectedPeople; }
                set
                {
                    selectedPeople = value;
                    this.NotifyPropertyChanged(p => p.SelectedPeople);
                }
            }
    
            public ObservableCollection<People> Peoples { get; set; }
    
    
            #region 多选
    
            private IEnumerable<People> selectedPeoples;
            public IEnumerable<People> SelectedPeoples
            {
                get { return selectedPeoples; }
                set
                {
                    selectedPeoples = value;
                    this.NotifyPropertyChanged(p => p.SelectedPeoples);
                }
            }
    
            private int numberOfItemsSelected;
            public int NumberOfItemsSelected
            {
                get { return numberOfItemsSelected; }
                set
                {
                    numberOfItemsSelected = value;
                    this.NotifyPropertyChanged(p => p.NumberOfItemsSelected);
                }
            }
    
            public RelayCommand<IList> SelectionChangedCommand { get; set; }
    
            private void SelectionChanged(IList items)
            {
                if (items != null)
                {
                    SelectedPeoples = items.Cast<People>();
                    NumberOfItemsSelected = items.Count;
                }
                else
                {
                    SelectedPeoples = null;
                    NumberOfItemsSelected = 0;
                }
            }
            #endregion
        }

        再定义一个Converter用于显示多个选择的People到textblock上:

        public class SelectedPeoplesConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                IEnumerable<People> SelectedPeoples = value as IEnumerable<People>;
                if (SelectedPeoples != null)
                {
                    return string.Join(
                        "|",
                        SelectedPeoples.Select(p => string.Format("姓名:{0},年龄:{1}   ", p.Name, p.Age))
                        );
                }
    
                return string.Empty;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

        再添加我们的Demo2.xaml,这里Command的绑定用到了System.Windows.Interactivity.dll:

    <UserControl x:Class="LWME.MVVMExperience.Views.Demo2"
        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"
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:v="clr-namespace:LWME.MVVMExperience.Views"
        xmlns:vm="clr-namespace:LWME.MVVMExperience.ViewModel"
        xmlns:cv="clr-namespace:LWME.MVVMExperience.Common"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
        <UserControl.Resources>
            <vm:PeopleViewModel x:Key="vm1" />
            <cv:SelectedPeoplesConverter x:Key="pc1" />
        </UserControl.Resources>
        <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource vm1}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="400" />
            </Grid.ColumnDefinitions>
            <sdk:DataGrid x:Name="peoplesDataGrid" Grid.Column="0" ItemsSource="{Binding Peoples}" SelectedItem="{Binding SelectedPeople, Mode=TwoWay}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction
                            Command="{Binding SelectionChangedCommand, Mode=OneWay}"
                            CommandParameter="{Binding SelectedItems, ElementName=peoplesDataGrid}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </sdk:DataGrid>
            <StackPanel Grid.Column="1" HorizontalAlignment="Center">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text=" 总共选中了:" />
                    <TextBlock Text="{Binding NumberOfItemsSelected}" />
                    <TextBlock Text="条记录,分别为:" />
                </StackPanel>
                <TextBlock Text="{Binding SelectedPeoples, Converter={StaticResource pc1}}" TextWrapping="Wrap" />
                <TextBlock Text=" 当前选中:" />
                <v:PeopleView DataContext="{Binding SelectedPeople}" />
            </StackPanel>
        </Grid>
    </UserControl>

    运行一下,选中多个列的时候,右边同时显示出了多个被选中的People数据以及选中的数目。

    总结一下,良好的分离使MVVM看起来蛮优雅的,而且熟悉了以后,有利于简化代码以及提高开发效率,over。

    DEMO在这里。。。

  • 相关阅读:
    select、poll和epoll
    Linux 常用命令之文件和目录
    SmartPlant Review 帮助文档机翻做培训手册
    SmartPlant Foundation 基础教程 3.4 菜单栏
    SmartPlant Foundation 基础教程 3.3 标题栏
    SmartPlant Foundation 基础教程 3.2 界面布局
    SmartPlant Foundation 基础教程 3.1 DTC登陆界面
    SmartPlant Foundation 基础教程 1.4 SPF架构
    SmartPlant Foundation 基础教程 1.3 SPF其他功能
    SmartPlant Foundation 基础教程 1.2 SPF集成设计功能
  • 原文地址:https://www.cnblogs.com/lwme/p/1785550.html
Copyright © 2011-2022 走看看