BabyShark 发表于 2022-10-6 17:44:07

如何在WPF开发中将静态Datagrid绑定到另一个类的List属性

本帖最后由 BabyShark 于 2022-10-6 17:48 编辑

最近做项目遇到一个问题,因为我对绑定和依赖属性理解不深所以不知道怎么解决。

我有一个Listbox控件和Datagrid控件。Datagrid里第一列是Checkbox,后面是Textbox,所有显示的数据源自一个Excel表格,我加载后在Datagrid里展示。Listbox里有n个项目,我们先假设有3个。
要求是,Datagrid里的数据除非直接在GUI里手动修改,不然保持不变,无论我对其他控件做什么操作。而且就算在GUI里手动修改了也不需要在数据源里更新,修改仅对当前的运行时有效,当我重启这个程序的时候显示的数据还是跟原来一样。这个Datagrid类似一个数据池以供用户选择。代表该数据结构的类如下:
public class ExcelDataEntry
{
   public bool isChecked { get; set; }
   public string note { get; set; }
   public ExcelDataEntry(string note)
   {
         this.isChecked = false;
         this.note = note;
   }
}

Listbox里的每一项都是一个viewModelObj类的实例,这个类主要含有一个displayName属性和一个List<ExcelDataEntry>属性,用于存储Datagrid里选中的数据行。该类结构如下:
class viewModelObj : INotifyPropertyChanged
{
   public string displayName { get; set; }
   
   private List<ExcelDataEntry> _generalNoteList;
   public List<ExcelDataEntry> generalNoteList
   {
         get { return _generalNoteList; }
         set
         {
             _generalNoteList = value;
             OnPropertyChanged("generalNoteList");
             MessageBox.Show($"generalNoteList changed from model.");
         }
   }
   
   public viewModelObj(string name)
   {
         displayName = name;
   }
   
   #region INotifyPropertyChanged Members
   public event PropertyChangedEventHandler PropertyChanged;
   
   private void OnPropertyChanged( string propertyName = "")
   {
         if (PropertyChanged != null)
         {
             PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
         }
   }
   #endregion
}

我尝试整个开发遵循MVVM模式,其中view model代码如下:
class ChangeRequestViewModel
{
         public ObservableCollection<ExcelDataEntry> generalNoteSource { get; set; } = new ObservableCollection<ExcelDataEntry>();
         public ObservableCollection<viewModelObj> viewModelSource { get; set; } = new ObservableCollection<viewModelObj>();
      
         public ChangeRequestViewModel()
         {
             List<ExcelDataEntry> dataPool = Default.GenerateDataPool("data.xlsx", 1, 4, 1, 71, 5);
             foreach (var entry in dataPool.Where(x => x.note == "GN").ToList())
             {
               this.generalNoteSource.Add(entry);
             }
             CatDocFactory catDocFactory = new CatDocFactory();
             foreach (var entry in catDocFactory.GetAllOpenedDocs())
             {
               this.viewModelSource.Add(new viewModelObj(entry.displayName));
             }
         }   
}
这其中,generalNoteSource是Datagrid里的数据来源,viewModelSource是Listbox里的数据来源。
Main.cs如下:
public partial class MainWindow : Window
{
   Window parentWindow;
   private ChangeRequestViewModel changeRequestDataContext;
   
   public MainWindow(Window window)
   {
         InitializeComponent();
         parentWindow = window;
         parentWindow.Visibility = Visibility.Hidden;
         LoadDefaultData();
   }
   
   private void LoadDefaultData()
   {
         changeRequestDataContext = new ChangeRequestViewModel();
   }
   
   private void export_Click(object sender, RoutedEventArgs e)
   {
         List<CatDocumentInView> output = changeRequestDataContext.viewModelSource.ToList();
   }
}

XAML结构如下:
<Window x:Class="A350F_Change_Request.MainWindow"
   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:local="clr-namespace:A350F_Change_Request" xmlns:changeRequestVM="clr-namespace:A350F_Change_Request.ViewModels"
   mc:Ignorable="d"
   Title="MainWindow" Height="648"Width="1104.25" MinWidth="1148" MinHeight="648" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
   <Window.DataContext>
         <changeRequestVM:ChangeRequestViewModel/>
   </Window.DataContext>
   <Window.Resources>
         <Style TargetType="{x:Type TabControl}">
             <Setter Property="TabStripPlacement" Value="Top" />
             <Setter Property="Margin" Value="0" />
             <Setter Property="Padding" Value="0"/>
         </Style>
   
         <Style TargetType="TabItem">
             <Setter Property="FontSize" Value="10"/>
             <Setter Property="BorderBrush" Value="Pink"/>
             <Setter Property="BorderThickness" Value="10"/>
             <Setter Property="Template">
               <Setter.Value>
                     <ControlTemplate TargetType="{x:Type TabItem}">
                         <Border x:Name="tabItemBorder" Background="{TemplateBinding Background}" BorderThickness="1,1,1,0"
   BorderBrush="Black" Margin="0,0,0,0" CornerRadius="2,2,0,0" Padding="50,0,50,0">
                           <ContentPresenter ContentSource="Header" Margin="5" />
                         </Border>
                         <ControlTemplate.Triggers>
                           <Trigger Property="IsSelected" Value="True">
                                 <Setter Property="Background" Value="#fff291"/>
                                 <Setter Property="Foreground" Value="#000"/>
                           </Trigger>
   
                           <Trigger Property="IsSelected" Value="false">
                                 <Setter Property="Background" Value="#013268"/>
                                 <Setter Property="Foreground" Value="#fff"/>
                           </Trigger>
                         </ControlTemplate.Triggers>
   
                     </ControlTemplate>
               </Setter.Value>
             </Setter>
         </Style>
   
         <Style TargetType="ListBoxItem" x:Key="ContainerStyle">
             <Style.Triggers>
               <Trigger Property="IsSelected" Value="True" >
                     <Setter Property="Background" Value="#fff291"/>
                     <Setter Property="Foreground" Value="#000"/>
               </Trigger>
               <Trigger Property="IsSelected" Value="False" >
                     <Setter Property="Foreground" Value="White"/>
                     <Setter Property="Background" Value="#013268"/>
               </Trigger>
             </Style.Triggers>
         </Style>
   </Window.Resources>
   <Grid x:Name="mainGrid" Background="#FF111F74" HorizontalAlignment="Left" Height="619" VerticalAlignment="Top" Width="1142">
         <Grid.RowDefinitions>
             <RowDefinition Height="3*"/>
             <RowDefinition Height="4*"/>
         </Grid.RowDefinitions>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="*"/>
             <ColumnDefinition Width="3*"/>
         </Grid.ColumnDefinitions>
         <Border Grid.Column="0" Grid.RowSpan="2" Background="#FF111F74"/>
         <Border Grid.Column="1" Background="#FF111F74"/>
         <Border Grid.Column="1" Grid.Row="1" Background="#FF111F74"/>
         <ListBox x:Name="catDocListView" Grid.Column="0" Grid.RowSpan="2" Margin="16" ItemContainerStyle="{StaticResource ContainerStyle}"ItemsSource="{Binding viewModelSource}" DisplayMemberPath="displayName"/>
   
         <StackPanel Grid.Column="1" Margin="16" Background="white" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
             <Grid>
               <Grid.ColumnDefinitions>
                     <ColumnDefinition/>
                     <ColumnDefinition/>
                     <ColumnDefinition/>
                     <ColumnDefinition/>
                     <ColumnDefinition/>
                     <ColumnDefinition/>
               </Grid.ColumnDefinitions>
               <Grid.RowDefinitions>
                     <RowDefinition/>
                     <RowDefinition/>
                     <RowDefinition/>
               </Grid.RowDefinitions>
               <Label Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16">Material:</Label>
               <ComboBox x:Name="materialCombo" Grid.Column="1" HorizontalAlignment="Stretch" Margin="8" ItemsSource="{Binding Path=materialSource}"Text="{Binding ElementName=catDocListView, Path=SelectedItem.Material}"/>
               <Label Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16">ECN:</Label>
             </Grid>
   
             <TextBox Margin="8" Height="80" TextWrapping="Wrap" AcceptsReturn="True" Text="{Binding ElementName=catDocListView, Path=SelectedItem.ECN, Mode=TwoWay}"/>
             <Button x:Name="export" Width="80" Height="20" Content="Export" HorizontalAlignment="Right" Margin="0,0,16,0" Click="export_Click"></Button>
         </StackPanel>
         <TabControl Grid.Row="1" Grid.Column="1" Margin="16">
             <TabItem Header="General Notes" FontSize="16">
               <DataGrid x:Name="generalNoteDG" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding generalNoteSource}">
                     <DataGrid.Columns>
                         <DataGridCheckBoxColumn Binding="{Binding isChecked}"/>
                         <DataGridTextColumn Header="Note" Binding="{Binding note}" Width="Auto"/>
                         <DataGridTextColumn Header="No" Binding="{Binding no}" Width="Auto"/>
                         <DataGridTextColumn Header="English Note" Binding="{Binding eng}" Width="Auto"/>
                         <DataGridTextColumn Header="German Note" Binding="{Binding deu}" Width="Auto"/>
                     </DataGrid.Columns>
               </DataGrid>
             </TabItem>
         </TabControl>
   </Grid>
</Window>

我现在的问题就是如何实现,当我选中一个Listbox项后,如何在每次选中Datagrid里的Checkbox后,代表改行的实例被存储进那个Listbox项的generalNoteList里,删除同样。

我不清楚是否我的设计有问题,我需要修改XAML的设计才能实现这个功能。
页: [1]
查看完整版本: 如何在WPF开发中将静态Datagrid绑定到另一个类的List属性