本帖最后由 BabyShark 于 2022-10-6 17:48 编辑
最近做项目遇到一个问题,因为我对绑定和依赖属性理解不深所以不知道怎么解决。
我有一个Listbox控件和Datagrid控件。Datagrid里第一列是Checkbox,后面是Textbox,所有显示的数据源自一个Excel表格,我加载后在Datagrid里展示。Listbox里有n个项目,我们先假设有3个。
要求是,Datagrid里的数据除非直接在GUI里手动修改,不然保持不变,无论我对其他控件做什么操作。而且就算在GUI里手动修改了也不需要在数据源里更新,修改仅对当前的运行时有效,当我重启这个程序的时候显示的数据还是跟原来一样。这个Datagrid类似一个数据池以供用户选择。代表该数据结构的类如下:
[C#] 纯文本查看 复制代码 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里选中的数据行。该类结构如下:
[C#] 纯文本查看 复制代码 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([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
我尝试整个开发遵循MVVM模式,其中view model代码如下:
[C#] 纯文本查看 复制代码 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如下:
[C#] 纯文本查看 复制代码 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结构如下:
[XML] 纯文本查看 复制代码 <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的设计才能实现这个功能。
|