主從結構在企業級應用中至關常見,這裏結合個人例子談一下wpf中主從結構列表展現的經常使用作法,具體效果見 wpf企業級開發中的幾種常見業務場景。html
首先,Model有兩種,主表對應model(假設爲modelA),從表對應的model(假設爲modelB),兩種model分別用於綁定列表,就是普通列表的綁定。ide
其次,因爲要實現聯動效果(即選擇主表中的一條記錄顯示從表的記錄),故而咱們的ViewModel裏面必須設計一個SelectedModelA用來綁定選中項,SelectedModelA變化時去更新modelB列表的數據源(一般SelectedModelA中會包含一個集合,不過我這裏因爲其餘緣由單獨弄了個集合,邏輯其實大同小異)。url
下面是個人代碼,因爲夾雜着一些業務,僅供參考,其實讀者只需明白主表的選中項做爲從表UI的數據源便可。spa
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中相關代碼code
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的狀態)htm