WPF 数据集合绑定到DataGrid、ListView或者其他列表控件

需求描述

需要使用一个类似表格的控件,数据格式如下:

数据名称数据标记数据值选择
DataAtrueKea(可选的值:Kea,Lau,Nuh)
DataBtrueLau(可选的值:Kea,Lau,Nuh)
DataCtrueinvalid(可选的值:invalid,valid)
DataDfalseinvalid(可选的值:invalid,valid)
DataEtrue0(可选的值:0,1,2,3,4,5,6)
DataFtrue100(可选的值:0,20,40,60,80,100,120,140,160,180,200)
DataGtrue3(可选的值:0,1,2,3,4,5,6)

 

 

需求分析

  • 界面实现分析:

    可以看出,我们的数据排列为:名称、标识和值。名称可以通过TextBlock之类的标签控件实现,标识可以使用CheckBox或者ToggleButton实现;最后的值典型的需要使用下拉列表框(ComboBoxListBox等)。

    能够实现以上布局的有:①表格(DataGrid);②列表(ListBoxListViewItemControl);③自定义控件布局(数据有限和确定的情况下可以考虑)。本次对前两种进行讨论。

    DataGrid具备行、列的形式,因此很容易想到。每列我们分别使用DataGridTextColumnDataGridCheckBoxColumnDataGridComboBoxColumn即可完成。

    列表典型的列结构,不伦我们使用哪种列表,都需要自定义一个数据模板,用以实现我们

  • 数据结构分析:

    我们数据其实非常有规律,可以将其结构定义如下:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Controls;

namespace Melphi.UiCore
{
    /// <summary>
    /// ListViewsView.xaml 的交互逻辑
    /// </summary>
    public partial class ListViewsView : UserControl
    {
        public ListViewsView()
        {
            InitializeComponent();
        }

        private ObservableCollection<MelphiDataItem> melphiDataSource = new ObservableCollection<MelphiDataItem>();

        /// <summary>
        /// 数据源
        /// </summary>
        public ObservableCollection<MelphiDataItem> MelphiDataSource
        {
            get
            {
                return melphiDataSource;
            }
            set
            {
                melphiDataSource = value;
            }
        }
    }

    /// <summary>
    /// 数据项
    /// </summary>
    public class MelphiDataItem
    {
        /// <summary>
        /// 数据名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 数据标识
        /// </summary>
        public bool IsEnabled { get; set; }

        /// <summary>
        /// 设定值
        /// </summary>
        public string SelectedValue { get; set; }

        /// <summary>
        /// 设定值选定项集合
        /// </summary>
        public List<string> SelectionSource { get; set; }

    }
}

稍做说明:每个数据项就是一个MelphiDataItem的实例,使用变化自动通知界面的集合ObservableCollection来存储所有的数据。

 

设计实现

  • 初始化数据

一般情况下,我们的数据获取来源一般由文件、服务器或者数据库获得,为了方便,这里就直接在程序里面定义了。

public class MelphiDataService
    {
        /// <summary>
        /// 模拟获取数据源
        /// </summary>
        /// <returns></returns>
        public static ObservableCollection<MelphiDataItem> GetDataSource()
        {
            ObservableCollection<MelphiDataItem> melphiDatas = new ObservableCollection<MelphiDataItem>();
​
            melphiDatas.Add(new MelphiDataItem()
            {
                Name = "DataA",
                IsEnabled = true,
                SelectedValue = "Kea",
                SelectionSource = new List<string>() { "Kea", "Lau", "Nuh" }
            });
​
            melphiDatas.Add(new MelphiDataItem()
            {
                Name = "DataB",
                IsEnabled = true,
                SelectedValue = "Lau",
                SelectionSource = new List<string>() { "Kea", "Lau", "Nuh" }
            });
​
            melphiDatas.Add(new MelphiDataItem()
            {
                Name = "DataC",
                IsEnabled = true,
                SelectedValue = "invalid",
                SelectionSource = new List<string>() { "invalid", "valid" }
            });
​
            melphiDatas.Add(new MelphiDataItem()
            {
                Name = "DataD",
                IsEnabled = true,
                SelectedValue = "invalid",
                SelectionSource = new List<string>() { "invalid", "valid" }
            });
​
            melphiDatas.Add(new MelphiDataItem()
            {
                Name = "DataE",
                IsEnabled = false,
                SelectedValue = "0",
                SelectionSource = new List<string>() { "0", "1", "2", "3", "4", "5", "6" }
            });
​
            var listsource = new List<string>();
            for (int i = 0; i <= 200; i+=20)
            {
                listsource.Add(i.ToString());
            }
​
            melphiDatas.Add(new MelphiDataItem()
            {
                Name = "DataF",
                IsEnabled = true,
                SelectedValue = "100",
                SelectionSource = listsource
            });
​
            melphiDatas.Add(new MelphiDataItem()
            {
                Name = "DataG",
                IsEnabled = true,
                SelectedValue = "3",
                SelectionSource = new List<string>() { "0", "1", "2", "3", "4", "5", "6" }
            });
​
            return melphiDatas;
        }
    }

在程序视图构造时获取数据,并将数据复制给我们界面绑定的数据源。

public partial class ListViewsView : UserControl
    {
        public ListViewsView()
        {
            InitializeComponent();

            // 获取数据源
            MelphiDataSource = MelphiDataService.GetDataSource();
        }

        private ObservableCollection<MelphiDataItem> melphiDataSource = new ObservableCollection<MelphiDataItem>();

        /// <summary>
        /// 数据源
        /// </summary>
        public ObservableCollection<MelphiDataItem> MelphiDataSource
        {
            get
            {
                return melphiDataSource;
            }
            set
            {
                melphiDataSource = value;
            }
        }
    }
using System.Collections.ObjectModel;
using System.Windows.Controls;

namespace Melphi.UiCore
{
    /// <summary>
    /// DataGridsView.xaml 的交互逻辑
    /// </summary>
    public partial class DataGridsView : UserControl
    {
        public DataGridsView()
        {
            InitializeComponent();

            // 获取数据源
            MelphiDataSource = MelphiDataService.GetDataSource();
        }

        private ObservableCollection<MelphiDataItem> melphiDataSource = new ObservableCollection<MelphiDataItem>();

        /// <summary>
        /// 数据源
        /// </summary>
        public ObservableCollection<MelphiDataItem> MelphiDataSource
        {
            get
            {
                return melphiDataSource;
            }
            set
            {
                melphiDataSource = value;
            }
        }
    }
}
  • 界面设计以及数据绑定

  • ListView
<UserControl x:Class="Melphi.UiCore.ListViewsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Melphi.UiCore"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <WrapPanel>
            <StackPanel>
                <!-- 标题 -->
                <ListView HorizontalAlignment="Left"
                      BorderBrush="Black" BorderThickness="1" Margin="20 20 20 0" >
                    <ListViewItem>
                        <Border BorderBrush="Black" BorderThickness="1">
                            <Grid Width="500" >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="3*"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="1.5*"/>
                                </Grid.ColumnDefinitions>

                                <TextBlock Grid.Column="0" VerticalAlignment="Center" Text="Name"/>

                                <Border Grid.Column="1">
                                    <TextBlock  VerticalAlignment="Center" Text="IsEnabled"/>
                                </Border>
                                <TextBlock Grid.Column="2" VerticalAlignment="Center" Text="Value"/>

                            </Grid>
                        </Border>
                    </ListViewItem>
                </ListView>
                <!-- 内容 -->
                <ListView HorizontalAlignment="Left"
                          BorderBrush="Black" BorderThickness="1" Margin="20 0 20 20" 
                          ItemsSource="{Binding Path=MelphiDataSource,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <Border BorderBrush="Black" BorderThickness="1">
                                <Grid Width="500" >
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="3*"/>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="1.5*"/>
                                    </Grid.ColumnDefinitions>

                                    <TextBlock Grid.Column="0" VerticalAlignment="Center" Text="{Binding Name}"/>

                                    <Border Grid.Column="1">
                                        <!-- 使用 ToggleButton 会让程序更好看,或者你重新定义控件模板来实现自己想要的效果 -->
                                        <!--<ToggleButton IsChecked="{Binding IsEnabled}" HorizontalAlignment="Stretch"/>-->
                                        <CheckBox IsChecked="{Binding IsEnabled}" HorizontalAlignment="Stretch"/>
                                    </Border>

                                    <ComboBox Grid.Column="2"  SelectedItem="{Binding SelectedValue}" ItemsSource="{Binding SelectionSource}" TextBlock.TextAlignment="Center" HorizontalAlignment="Stretch" >
                                    </ComboBox>
                                </Grid>
                            </Border>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>

        </WrapPanel>
    </Grid>
</UserControl>
  • DataGrid

<UserControl x:Class="Melphi.UiCore.DataGridsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Melphi.UiCore"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <WrapPanel>
            <DataGrid HorizontalAlignment="Left" Margin="10"
                      ItemsSource="{Binding Path=MelphiDataSource,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"
                      RowDetailsVisibilityMode="VisibleWhenSelected"
                      AutoGenerateColumns="False">
                <DataGrid.RowDetailsTemplate>
                    <DataTemplate>
                        <Border BorderThickness="0" Padding="5">
                            <StackPanel Orientation="Vertical">
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="Tips: " VerticalAlignment="Center"/>
                                    <TextBlock Text="{Binding Description}" VerticalAlignment="Center"
                                FontSize="15" FontWeight="Bold"/>
                                </StackPanel>
                            </StackPanel>
                        </Border>
                    </DataTemplate>
                </DataGrid.RowDetailsTemplate>
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" />
                    <!-- 使用 DataGrid 提供的列 -->
                    <DataGridCheckBoxColumn Header="IsActive" Binding="{Binding Path=IsEnabled}"/>
                    <!-- 使用自定义的列模板 -->
                    <DataGridTemplateColumn Header="Temp">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ToggleButton IsChecked="{Binding Path=IsEnabled,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>

                    <!-- 使用 DataGrid 提供的列,修改其样式满足我们的显示需要 -->
                    <!-- 注意:直接对其进行数据绑定是没有效果,这是关键点 -->
                    <DataGridComboBoxColumn Header="Value">
                        <DataGridComboBoxColumn.EditingElementStyle>
                            <Style TargetType="ComboBox">
                                <Setter Property="ItemsSource" Value="{Binding Path=SelectionSource}" />
                                <Setter Property="SelectedValue" Value="{Binding Path=SelectedValue}" />
                            </Style>
                        </DataGridComboBoxColumn.EditingElementStyle>
                        <DataGridComboBoxColumn.ElementStyle>
                            <Style TargetType="ComboBox">
                                <Setter Property="ItemsSource" Value="{Binding Path=SelectionSource}" />
                                <Setter Property="SelectedValue" Value="{Binding Path=SelectedValue}" />
                            </Style>
                        </DataGridComboBoxColumn.ElementStyle>
                    </DataGridComboBoxColumn>
                </DataGrid.Columns>
            </DataGrid>
        </WrapPanel>
    </Grid>
</UserControl>

注意:

1.使用DataGridComboBoxColumn作为数据列时,需要修改DataGridComboBoxColumnEditingElementStyleElementStyle,将我们数据绑定到这两个样式上的ItemsSourceSelectedValue上。如果直接绑定到DataGridComboBoxColumnItemsSourceSelectedValue上,我们的数据绑定是无效的。

2.DataGrid控件提供的列中,有一个非常方便的列控件——DataGridTemplateColumn。这个模板列控件可以按照我们的界面需求进行自定义界面样式和数据绑定。值得留意的是:DataGrid提供的默认列,如DataGridTextColumnDataGridCheckBoxColumnDataGridComboBoxColumn以及DataGridHyperlinkColumn在做数据绑定时,默认情况下数据绑定是双向更新的(数据模型<-->界面);但是DataGridTemplateColumn的默认绑定是单向的(数据模型-->界面),如果需要双向时,需要对绑定的数据 指定UpdateSourceTrigger,如下所示,而列表类的控件就没有这个细节。

 <!-- 使用自定义的列模板 -->
 <DataGridTemplateColumn Header="IsTemplate">
     <DataGridTemplateColumn.CellTemplate>
         <DataTemplate>
             <ToggleButton IsChecked="{Binding Path=IsEnabled,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
         </DataTemplate>
     </DataGridTemplateColumn.CellTemplate>
 </DataGridTemplateColumn>
  • 运行调试

 

总结

虽然完成之后觉得很简单没什么,但是我在最开始拿到需求到真正实现的过程中走了不少的弯路,从早上上班到下午3点才算解决。

现在回头,觉得自己之所以走弯路,主要的问题出现在对控件的不熟悉,其中DataGridDataGridComboBoxColumn数据绑定不成功耗费最多。其次是对自己定义的数据结构不信任,导致对数据结构的多次更换、重新实验。

还是列表控件拯救了我,相比DataGrid控件,自己对列表控件认识要更深一些(也许是他更简单一些吧),让我最终坚信我的数据结构没问题,"简单轻松"得完成了需求。

但是DataGrid控件确实是一个非常好的控件。我们可以看到他具备一些普通的列模板,虽然不能完全满足我们的需求。但是他提供了DataGridTemplateColumn列模板,我们可以根据我们的界面和数据需求进行自制模板。是不是很nice。不仅如此,该控件还提供了很多额外的功能,一般的编辑功能就不说了,还有选中提示功能如RowDetailsTemplate中定义了我们点击某一行时,的提示模板......总之,非常强,早学早轻松。

最后再说一点,在程序开发时,我们需要分析,尤其是对数据结构的分析,慢慢地你会得到极大提升。

 

 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Caliburn.Micro是一个轻量级的MVVM框架,它可以帮助你更轻松地编写WPF、UWP、WinRT、Windows Phone和Silverlight应用程序。以下是一些使用Caliburn.Micro的好处和建议: 1. MVVM架构:Caliburn.Micro基于MVVM架构,这使得你的代码更加容易维护和测试。你可以将应用程序分解成视图、视图模型和模型,这有助于你保持代码的分离和可读性。 2. 可扩展性:Caliburn.Micro是一个非常灵活的框架,它可以与许多其他框架和库集成。例如,你可以使用Caliburn.Micro与.NET Core、ReactiveUI、Autofac等等。 3. 命令绑定:Caliburn.Micro提供了一个简单的方法来绑定命令。你可以使用它来处理按钮点击、菜单项点击等事件。 4. 依赖注入:Caliburn.Micro包含一个简单的依赖注入容器,这使得你可以更容易地管理应用程序中的依赖关系。 5. 事件聚合器:Caliburn.Micro包含一个事件聚合器,这使得你可以更轻松地在应用程序中进行通信和事件处理。 如果你打算使用WPF或UWP来构建你的应用程序,那么我强烈推荐你使用Caliburn.Micro框架。它可以大大简化你的开发过程,使得你可以更加专注于实现业务逻辑和用户体验。 ### 回答2: Caliburn.Micro是一个开源的MVVM(Model-View-ViewModel)框架,可以帮助开发人员更轻松地构建WPF(Windows Presentation Foundation)和Silverlight应用程序。以下是我为什么推荐使用Caliburn.Micro的几个理由: 1. 简化MVVM开发模式:Caliburn.Micro使用约定优于配置的原则,采用了一系列命名规则和自动绑定功能来帮助开发人员快速构建MVVM应用程序,减少了繁琐的代码编写工作。 2. 低代码开发:相比于其他MVVM框架,Caliburn.Micro的代码量相对较少,而且框架已经内置了很多常见的功能,如路由导航、事件聚焦等,这些功能可以帮助开发人员减少代码编写,快速实现各种业务需求。 3. 容易扩展和定制:Caliburn.Micro框架提供了很多可扩展的点,可以根据自己的业务需求进行定制和扩展。通过使用框架提供的IoC容器和事件聚焦功能,可以方便地实现模块化开发和松耦合。 4. 强大的应用生命周期管理:Caliburn.Micro提供了全面的应用程序生命周期管理功能,包括应用程序的启动、关闭、暂停和恢复等。这些功能可以帮助开发人员更好地控制应用程序的状态和行为。 5. 大量的文档和社区支持:Caliburn.Micro在开源社区中有着广泛的应用和活跃的社区支持。它的官方网站上提供了大量的文档、示例代码和教程,方便开发人员学习和使用框架。 总的来说,Caliburn.Micro是一个功能强大、简化开发、易于扩展和定制的MVVM框架,适用于构建WPF和Silverlight应用程序。如果你想提高开发效率,同时保持代码的整洁和可扩展性,我强烈推荐你使用Caliburn.Micro。 ### 回答3: Caliburn.Micro是一个轻量级的MVVM(模型-视图-视图模型)框架,它能够帮助我们更轻松地开发WPF、Silverlight和Windows Phone应用程序。 首先,Caliburn.Micro具有简单易用的语法。它使用了一些约定来自动绑定视图和视图模型之间的关系,减少了冗余的代码量。例如,只需按照约定命名视图和视图模型,框架就会自动找到它们并建立绑定关系。 其次,Caliburn.Micro提供了一个灵活的导航系统。我们可以使用导航器来导航到不同的视图和视图模型,而无需直接在代码中管理窗口和页面的切换。这使得应用程序的导航逻辑更加清晰和可维护。 另外,Caliburn.Micro还提供了事件聚合器和消息机制,用于实现视图模型之间的松耦合通信。我们可以发送和订阅事件,通过消息来传递数据和触发操作,简化了模块间的交互。 最后,Caliburn.Micro还有一个活跃的社区支持。我们可以在官方网站上找到详细的文档和示例代码,以及各种问题的解决方案。社区成员也经常发布新的更新和扩展,使得框架的功能更加丰富和强大。 总结而言,Caliburn.Micro是一个强大且易用的MVVM框架,适用于开发WPF、Silverlight和Windows Phone应用程序。它的简单语法、灵活导航、松耦合通信和活跃的社区支持,使得我们能够更高效地开发出优秀的应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值