主从结构在企业级应用中相当常见,这里结合我的例子谈一下wpf中主从结构列表展示的常用做法,具体效果见 wpf企业级开发中的几种常见业务场景

  首先,Model有两种,主表对应model(假设为modelA),从表对应的model(假设为modelB),两种model分别用于绑定列表,就是普通列表的绑定。

  其次,由于要实现联动效果(即选择主表中的一条记录显示从表的记录),故而我们的ViewModel里面必须设计一个SelectedModelA用来绑定选中项,SelectedModelA变化时去更新modelB列表的数据源(通常SelectedModelA中会包含一个集合,不过我这里由于其他原因单独弄了个集合,逻辑其实大同小异)。

  下面是我的代码,由于夹杂着一些业务,仅供参考,其实读者只需明白主表的选中项作为从表UI的数据源即可。

  UI部分,可先直接看下具体效果 wpf企业级开发中的几种常见业务场景,绑定部分主要看两个DataGrid即可。

    <Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<HeaderedContentControl>
<HeaderedContentControl.Header>
<DockPanel>
<TextBlock VerticalAlignment="Center" Text="{DynamicResource ProductClassify_Header_Classify}" DockPanel.Dock="Left"/>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Horizontal">
<Button Name="Button_RefreshClassify" Style="{StaticResource RefreshIconButton}" Content="{DynamicResource Common_Refresh}" Command="{Binding TreeVM.RefreshCommand}"/>
</StackPanel>
</DockPanel>
</HeaderedContentControl.Header>
<local:ClassifyTreeControl DataContext="{Binding TreeVM}"/>
</HeaderedContentControl> <HeaderedContentControl Name="Header_Product" Grid.Column="1">
<HeaderedContentControl.Header>
<DockPanel>
<TextBlock VerticalAlignment="Center" Text="{DynamicResource ProductList_Header_Product}" DockPanel.Dock="Left"/>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Horizontal">
<Button Name="Button_RefreshClassify2" Style="{StaticResource RefreshIconButton}" Content="{DynamicResource Common_Refresh}" Command="{Binding RefreshCommand}"/>
<Button Name="Button_AddProduct" Visibility="{Binding AddButtonVisibility}" IsEnabled="{Binding CanAdd}" Style="{StaticResource AddIconButton}" Content="{DynamicResource Common_Add}" Click="Button_AddProduct_Click"/>
<Button Name="Button_ModifyProduct" Visibility="{Binding ModifyButtonVisibility}" IsEnabled="{Binding CanModify}" Style="{StaticResource ModifyIconButton}" Content="{DynamicResource Common_Modify}" Click="Button_ModifyProduct_Click"/>
<Button Name="Button_DeleteProduct" Visibility="{Binding DeleteButtonVisibility}" Style="{StaticResource DeleteIconButton}" Content="{DynamicResource Common_Delete}" Command="{Binding DeleteCommand}"/>
</StackPanel>
</DockPanel>
</HeaderedContentControl.Header>
<DataGrid Name="DataGrid_Product" ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedProduct}" SelectionMode="Single" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="{DynamicResource Product_Num}" Binding="{Binding Num}" Width="120"/>
<DataGridTextColumn Header="{DynamicResource Product_Name_CH}" Binding="{Binding Name_CH}" Width="100"/>
<DataGridTextColumn Header="{DynamicResource Product_Name_EN}" Binding="{Binding Name_EN}" Width="100"/>
<DataGridTextColumn Header="{DynamicResource Product_Unit}" Binding="{Binding Unit}" Width="50"/>
<DataGridTextColumn Header="{DynamicResource Product_Weight}" Binding="{Binding Weight}" Width="100"/>
<DataGridTextColumn Header="{DynamicResource Product_Size}" Binding="{Binding Size}" Width="100"/>
<DataGridTemplateColumn Header="{DynamicResource Product_CanSale}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsThreeState="False" IsChecked="{Binding CanSale}" IsEnabled="False" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" HorizontalAlignment="Center" Width="50"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="{DynamicResource Product_ReferencePrice}" Binding="{Binding ReferencePrice}" Width="100"/>
<DataGridTemplateColumn Header="{DynamicResource Product_StopProduction}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsThreeState="False" IsChecked="{Binding StopProduction}" IsEnabled="False" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" HorizontalAlignment="Center" Width="50"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="{DynamicResource Product_MinSaleCount}" Binding="{Binding MinSaleCount}" Width="80"/>
<DataGridTextColumn Header="{DynamicResource Product_PackageCount}" Binding="{Binding PackageCount}" Width="80"/>
<DataGridTextColumn Header="{DynamicResource Product_Remark}" Binding="{Binding Remark}" Width="200"/>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="ToolTip">
<Setter.Value>
<Border Width="100" Height="100" BorderBrush="#FF7DB6D8" BorderThickness="1" Padding="1">
<Border.Resources>
<product:PicUrlConverter x:Key="urlConverter"/>
</Border.Resources>
<Image Source="{Binding ProductPic, Converter={StaticResource urlConverter}}"/>
</Border>
</Setter.Value>
</Setter>
<EventSetter Event="MouseDoubleClick" Handler="Button_ModifyProduct_Click"/>
</Style>
</DataGrid.RowStyle>
</DataGrid>
</HeaderedContentControl>
</Grid>

  ViewModel中相关代码

    public class ProductListVM : ViewModelBase
{
public ProductListVM()
{
LoadData();
TreeVM.SelectedChanged += (s, e) =>
{
LoadData();
if (TreeVM.SelectedModel != null && !string.IsNullOrEmpty(TreeVM.SelectedModel.ID))
CanAdd = true;
else
CanAdd = false;
};
} private ClassifyTreeVM _treeVM;
public ClassifyTreeVM TreeVM
{
get
{
return _treeVM ?? (_treeVM = new ClassifyTreeVM());
}
} private tb_product _selectedProduct;
public tb_product SelectedProduct
{
get
{
return _selectedProduct;
}
set
{
_selectedProduct = value;
OnPropertyChanged("SelectedProduct");
if (value != null)
CanModify = true;
else
CanModify = false;
RaiseCanExecute();
}
} private List<tb_product> _products;
public List<tb_product> Products
{
get
{
return _products;
}
set
{
_products = value;
OnPropertyChanged("Products");
}
} protected override void LoadData()
{
if (TreeVM.SelectedModel != null && !string.IsNullOrEmpty(TreeVM.SelectedModel.ID))
Products = XDBContext.tb_product.Where(p => p.ClassifyID == TreeVM.SelectedModel.ID).AsNoTracking().ToList();
else
Products = XDBContext.tb_product.AsNoTracking().ToList();
} }
  public class ClassifyTreeVM : ViewModelBase
{
public ClassifyTreeVM()
{
LoadData();
} private BindingList<TB_ClassifyTreeModel> _classifyModels;
public BindingList<TB_ClassifyTreeModel> ClassifyModels
{
get
{
return _classifyModels;
}
set
{
_classifyModels = value;
OnPropertyChanged("ClassifyModels");
}
} public event EventHandler SelectedChanged; private TB_ClassifyTreeModel _selectedModel;
public TB_ClassifyTreeModel SelectedModel
{
get
{
return _selectedModel;
}
set
{
_selectedModel = value;
OnPropertyChanged("SelectedModeld");
if (SelectedChanged != null)
SelectedChanged(SelectedModel, null);
}
} protected override void LoadData()
{
ClassifyModels = new BindingList<TB_ClassifyTreeModel>();
ClassifyModels.Add(new TB_ClassifyTreeModel(XDBContext)
{
ClassifyName = "All",
ID = string.Empty
});
}
}

  关于主从结构编辑的保存,UI绑定就是一个主表model(包含从表集合),没什么特别的。只是在保存的时候一起保存从表信息即可(从表中可能有增删改,具体如何操作取决于数据操作层,数据少懒惰点的做法可以一股脑先将相关从表记录全删掉然后添加,这样就不用区分哪些记录是删除的、哪些是修改的及哪些是新添加的;通常有时候会在model中设计一个状态属性,以方便区分model的状态)

wpf企业应用之主从结构列表的更多相关文章

  1. wpf企业应用之SelectButton(用于列表页之类的选择)

    在企业级应用中,通常我们会遇到这样的需求,需要点击一个按钮选择列表中的一项或者多项,然后将结果显示到按钮中.这里我给自己的控件命名为SelectButton,具体效果见 wpf企业级开发中的几种常见业 ...

  2. WPF如何用TreeView制作好友列表、播放列表

    WPF如何用TreeView制作好友列表.播放列表 前言 TreeView这个控件对于我来说是用得比较多的,以前做的小聊天软件(好友列表).音乐播放器(播放列表).类库展示器(树形类结构)等都用的是T ...

  3. Angular2.js——主从结构

    学习这一篇的内容,还回到我们快速起步的应用上来. 主从结构,我们想要做一个英雄的列表,我们希望用户在列表中选中一个英雄,然后这个被选中的英雄出现在详情视图中.主视图是英雄列表,从视图则是被选中英雄的详 ...

  4. WPF如何用TreeView制作好友列表、播放列表(转)

    WPF如何用TreeView制作好友列表.播放列表 前言 TreeView这个控件对于我来说是用得比较多的,以前做的小聊天软件(好友列表).音乐播放器(播放列表).类库展示器(树形类结构)等都用的是T ...

  5. DWZ主从结构计算

    最终效果图: 首先我们需要修改一下主从结构的源码dwz.database.js,如下: function tdHtml(field){ var html='',suffix=''; if(field. ...

  6. MySql5.5以上版本设置主从结构的例子

    为了实现读写分离,一般都需要先设置好mysql的主从结构,网上现有的mysql配置大都基于低版本,在5.5以上版本无法配置成功,所以参考了官方文档,写了这篇笔记. *主要参考Mysql 5.6的官方文 ...

  7. WPF - Group分组对ListBox等列表样式的约束

    原文:WPF - Group分组对ListBox等列表样式的约束 在做WPF主题支持时,出现一个分组引起的莫名错误,可是折腾了我一番.在没有使用样式时,列表分组很正常,使用了别人写的ListBox列表 ...

  8. 为 WPF 程序添加 Windows 跳转列表的支持

    原文:为 WPF 程序添加 Windows 跳转列表的支持 Windows 跳转列表是自 Windows 7 时代就带来的功能,这一功能是跟随 Windows 7 的任务栏而发布的.当时应用程序要想用 ...

  9. Redis主从结构主节点执行写入后wait命令对性能的影响

    这里的Redis主从结构可以是简单的主从,sentinel,redis cluster中的主从等. wait命令的作用:此命令将阻塞当前客户端,直到当前Session连接(主节点上)所有的写命令都被传 ...

随机推荐

  1. 线段树区间更新(set暴力)

    题目链接:https://cn.vjudge.net/contest/66989#problem/I 具体思路:使用栈存储村庄被损坏的顺序,然后set存的是被损坏的村庄,然后每一次查询,直接找到要查询 ...

  2. Linux/Unix系统编程手册 第二章:基本概念

    本章预热与后续系统编程有关的概念. 术语“操作系统”通常包含2种含义:一是指完整的软件包,包括管理计算机资源的核心组件,已经附带的标准软件:二是独指管理硬件的内核. 内核具有诸多概功能,包括: 进程管 ...

  3. 五、springboot单元测试

    1.为什么要写测试用例 1. 可以避免测试点的遗漏,为了更好的进行测试,可以提高测试效率 2. 可以自动测试,可以在项目打包前进行测试校验 3. 可以及时发现因为修改代码导致新的问题的出现,并及时解决 ...

  4. js实现ctrl+v粘贴图片或是截图

    浏览器环境:谷歌浏览器 1.ctrl+v粘贴图片都是监听paste时间实现的,复制的数据都存在clipboardData下面,虽然打印显示数据长度为0,但是还是可以获取数据的 2.打印clipboar ...

  5. 【前端vue开发架构】vue开发单页项目架构总结

    为营销活动设计的前端架构 主要的技术栈为 Vuejs,Webpack,请自行阅读如下技术或者框架的文档: 一.基础说明: node (https://nodejs.org/en/) npm (http ...

  6. Dropout caffe源码

    GPU和CPU实现的不一样,这里贴的是CPU中的drop out 直接看caffe里面的源码吧:(产生满足伯努利分布的随机数mask,train的时候,data除以p,...... scale_ = ...

  7. java基础38 正则表达式

    1.常用的正则表达式  预定义字符类:.  任何字符(与行结束符可能匹配也可能不匹配) \d  数字:[0-9] \D  非数字: [^0-9] \s  空白字符:[ \t\n\x0B\f\r] \S ...

  8. 监控SQLServer作业执行情况脚本

    SELECT [sJOB].[job_id] AS [作业ID] , [sJOB].[name] AS [作业名] , CASE WHEN [sJOBH].[run_date] IS NULL OR ...

  9. Python学习笔记:出生日期转化为年龄

    在数据挖掘项目中,有时候个体的出生日期包含信息量过大,不适合作为一个有效数据进入模型算法训练,因此有必要把出生日期转化为年龄age,age是一个很好的特征工程指示变量. import pandas a ...

  10. 题解-python-CodeForces 227A

    codeforces题目,用python写 本题输入三个点坐标,考察叉积,若大于0则right,小于0则left,等于0则towards 代码: a = raw_input().split() b = ...