- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个自定义列标题,其中每个列的标题都有包含列名称的 TextBox
和包含列类型信息的 ComboBox
,例如“日期”、“编号”等
我正在尝试绑定(bind) ComboBox
并将其值保留在某处,以便当用户从 ComboBox
中选择新值时,我可以重新创建列类型已更改的表。基本上我所需要的就是以某种方式将每个 ComboBox
的值以某种方式存储在列表中。我想对 TextBox
做同样的事情,它应该包含列的名称。
这就是我目前所拥有的。
<DataGrid x:Name="SampleGrid" Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" ItemsSource="{Binding SampledData}">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding ., Mode=OneWay}"/>
<ComboBox>
// How can I set it from ViewModel?
<ComboBoxItem Content="Date"></ComboBoxItem>
<ComboBoxItem Content="Number"></ComboBoxItem>
</ComboBox>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
View 模型:
private DataTable _sampledData = new DataTable();
public DataTable SampledData
{
get => _sampledData;
set { _sampledData = value; NotifyOfPropertyChange(() => SampledData); }
}
只要我稍后可以将映射传递给 ViewModel,也欢迎代码隐藏的解决方案。
编辑:我一直在尝试使用 ViewModels 的 List
来完成这项工作,但没有成功:
public class ShellViewModel : Screen
{
public List<MyRowViewModel> Rows { get; set; }
public ShellViewModel()
{
Rows = new List<MyRowViewModel>
{
new MyRowViewModel { Column1 = "Test 1", Column2= 1 },
new MyRowViewModel { Column1 = "Test 2", Column2= 2 }
};
}
}
查看
<DataGrid ItemsSource="{Binding Rows}">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding ., Mode=OneWay}"/>
<ComboBox ItemsSource="{Binding ??????}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
行
public class MyRowViewModel : PropertyChangedBase
{
public string Column1 { get; set; }
public int Column2 { get; set; }
}
编辑2:
澄清一下,我需要一个能够处理动态列数的解决方案,因此一些文件可能存储 3 列,而一些可能存储 40 列。我用它来解析 csv 文件以稍后显示数据。为此,我必须知道文件包含哪些类型的值。因为某些类型可能不明确,所以我让用户决定他们想要哪种类型。这与 Excel 的“从文件加载”向导相同。
向导加载一小块数据(100 条记录)并允许用户决定列的类型。它会自动将列解析为:
68.35
不能被解析为 DateTime
)另一件事是命名每一列。有人可能会加载名为 C1
、C2
... 的每一列的 csv,但他们想分配有意义的名称,例如 Temperature
、Average
。这当然也必须稍后解析,因为两列不能有相同的名称,但一旦我有一个可绑定(bind)的 DataGrid
,我就可以处理这个问题。
最佳答案
让我们将您的问题分解成多个部分并分别解决每个部分。
首先,DataGrid
itemsource
,为了方便起见,假设我们的DataGrid
只有两个列,第 1 列 和第 2 列。 DataGrid
项的基本模型应如下所示:
public class DataGridModel
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
}
现在,假设您有一个 MainWindow
(ViewModel 或 DataContext
设置为代码隐藏),其中有一个 DataGrid
,让我们将 DataGridCollection
定义为其 ItemSource
:
private ObservableCollection<DataGridModel> _dataGridCollection=new ObservableCollection<DataGridModel>()
{
new DataGridModel(){FirstProperty = "first item",SecondProperty = "second item"},
new DataGridModel(){FirstProperty = "first item",SecondProperty = "second item"},
new DataGridModel(){FirstProperty = "first item",SecondProperty = "second item"}
};
public ObservableCollection<DataGridModel> DataGridCollection
{
get { return _dataGridCollection; }
set
{
if (Equals(value, _dataGridCollection)) return;
_dataGridCollection = value;
OnPropertyChanged();
}
}
其次,现在是有趣的部分,列结构。让我们为您的 DataGrid
列定义一个模型,该模型将包含设置您的 DataGrid
列所需的所有属性,包括:
-DataTypesCollection: 包含组合框项目源的集合。-HeaderPropertyCollection:一个元组集合,每个元组
代表一个列名和一个数据类型,数据类型基本上是列的 combobox
的选定项。
public class DataGridColumnsModel:INotifyPropertyChanged
{
private ObservableCollection<string> _dataTypesCollection = new ObservableCollection<string>()
{
"Date","String","Number"
};
public ObservableCollection<string> DataTypesCollection
{
get { return _dataTypesCollection; }
set
{
if (Equals(value, _dataTypesCollection)) return;
_dataTypesCollection = value;
OnPropertyChanged();
}
}
private ObservableCollection<Tuple<string, string>> _headerPropertiesCollection=new ObservableCollection<Tuple<string, string>>()
{
new Tuple<string, string>("Column 1", "Date"),
new Tuple<string, string>("Column 2", "String")
}; //The Dictionary has a PropertyName (Item1), and a PropertyDataType (Item2)
public ObservableCollection<Tuple<string,string>> HeaderPropertyCollection
{
get { return _headerPropertiesCollection; }
set
{
if (Equals(value, _headerPropertiesCollection)) return;
_headerPropertiesCollection = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
现在在 MainWindow 的 View 模型(或代码隐藏)中定义一个 DataGridColumnsModel
实例,我们将使用它来保存我们的 DataGrid
结构:
private DataGridColumnsModel _dataGridColumnsModel=new DataGridColumnsModel();
public DataGridColumnsModel DataGridColumnsModel
{
get { return _dataGridColumnsModel; }
set
{
if (Equals(value, _dataGridColumnsModel)) return;
_dataGridColumnsModel = value;
OnPropertyChanged();
}
}
第三,获取列的TextBox
的值。为此,我们将使用 MultiBinding
和 MultiValueConverter
,将传递给 MultiBinding
的第一个属性是我们定义的元组(列的名称和数据类型):HeaderPropertyCollection
,第二个是当前列索引,它将使用祖先绑定(bind)到 DisplayIndex
检索 DataGridColumnHeader
:
<TextBox >
<TextBox.Text>
<MultiBinding Converter="{StaticResource GetPropertConverter}">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type Window}}" Path="DataGridColumnsModel.HeaderPropertyCollection"/>
<Binding Path="DisplayIndex" Mode="OneWay" RelativeSource="{RelativeSource RelativeSource={x:Type DataGridColumnHeader}}"/>
</MultiBinding>
</TextBox.Text>
转换器将使用元组集合中的索引简单地检索正确的项目:
public class GetPropertConverter:IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
try
{
var theCollection = values[0] as ObservableCollection<Tuple<string, string>>;
return (theCollection?[(int)values[1]])?.Item1; //Item1 is the column name, Item2 is the column's ocmbobox's selectedItem
}
catch (Exception)
{
//use a better implementation!
return null;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
第四,最后一部分是在选择Combobox
时更新DataGrid
的ItemSource
已更改,因为您可以使用 System.Windows.Interactivity 命名空间中定义的交互工具(它是 Expression.Blend.Sdk 的一部分,使用 NuGet 来安装它:< em>安装包 Expression.Blend.Sdk):
<ComboBox ItemsSource="{Binding DataGridColumnsModel.DataTypesCollection,RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateItemSourceCommand,RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
每次 selectionChanged
事件发生时,在 UpdateItemSourceCommand
中更新您的 DataGrid
的 ItemSource
添加到您的主窗口的 ViewModel:
private RelayCommand _updateItemSourceCommand;
public RelayCommand UpdateItemSourceCommand
{
get
{
return _updateItemSourceCommand
?? (_updateItemSourceCommand = new RelayCommand(
() =>
{
//Update your DataGridCollection, you could also pass a parameter and use it.
//Update your DataGridCollection based on DataGridColumnsModel.HeaderPropertyCollection
}));
}
}
注意:我使用的 RelayCommand
类是 GalaSoft.MvvmLight.Command
命名空间的一部分,您可以通过 NuGet 添加它,或定义您自己的命令。
最后是完整的 xaml 代码:
Window x:Class="WpfApp1.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:WpfApp1"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<local:GetPropertConverter x:Key="GetPropertConverter"/>
</Window.Resources>
<Grid>
<DataGrid x:Name="SampleGrid" ItemsSource="{Binding DataGridCollection}" AutoGenerateColumns="False">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBox >
<TextBox.Text>
<MultiBinding Converter="{StaticResource GetPropertConverter}">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type Window}}" Path="DataGridColumnsModel.HeaderPropertyCollection"/>
<Binding Path="DisplayIndex" Mode="OneWay" RelativeSource="{RelativeSource AncestorType={x:Type DataGridColumnHeader}}"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
<ComboBox ItemsSource="{Binding DataGridColumnsModel.DataTypesCollection,RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateItemSourceCommand,RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="First Column" Binding="{Binding FirstProperty}" />
<DataGridTextColumn Header="Second Column" Binding="{Binding SecondProperty}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
并查看模型/代码隐藏:
public class GetPropertConverter:IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
try
{
var theCollection = values[0] as ObservableCollection<Tuple<string, string>>;
return (theCollection?[(int)values[1]])?.Item1; //Item1 is the column name, Item2 is the column's ocmbobox's selectedItem
}
catch (Exception)
{
//use a better implementation!
return null;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class DataGridColumnsModel:INotifyPropertyChanged
{
private ObservableCollection<string> _dataTypesCollection = new ObservableCollection<string>()
{
"Date","String","Number"
};
public ObservableCollection<string> DataTypesCollection
{
get { return _dataTypesCollection; }
set
{
if (Equals(value, _dataTypesCollection)) return;
_dataTypesCollection = value;
OnPropertyChanged();
}
}
private ObservableCollection<Tuple<string, string>> _headerPropertiesCollection=new ObservableCollection<Tuple<string, string>>()
{
new Tuple<string, string>("Column 1", "Date"),
new Tuple<string, string>("Column 2", "String")
}; //The Dictionary has a PropertyName (Item1), and a PropertyDataType (Item2)
public ObservableCollection<Tuple<string,string>> HeaderPropertyCollection
{
get { return _headerPropertiesCollection; }
set
{
if (Equals(value, _headerPropertiesCollection)) return;
_headerPropertiesCollection = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class DataGridModel
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
}
public partial class MainWindow : Window,INotifyPropertyChanged
{
private RelayCommand _updateItemSourceCommand;
public RelayCommand UpdateItemSourceCommand
{
get
{
return _updateItemSourceCommand
?? (_updateItemSourceCommand = new RelayCommand(
() =>
{
//Update your DataGridCollection, you could also pass a parameter and use it.
MessageBox.Show("Update has ocured");
}));
}
}
private ObservableCollection<DataGridModel> _dataGridCollection=new ObservableCollection<DataGridModel>()
{
new DataGridModel(){FirstProperty = "first item",SecondProperty = "second item"},
new DataGridModel(){FirstProperty = "first item",SecondProperty = "second item"},
new DataGridModel(){FirstProperty = "first item",SecondProperty = "second item"}
};
public ObservableCollection<DataGridModel> DataGridCollection
{
get { return _dataGridCollection; }
set
{
if (Equals(value, _dataGridCollection)) return;
_dataGridCollection = value;
OnPropertyChanged();
}
}
private DataGridColumnsModel _dataGridColumnsModel=new DataGridColumnsModel();
public DataGridColumnsModel DataGridColumnsModel
{
get { return _dataGridColumnsModel; }
set
{
if (Equals(value, _dataGridColumnsModel)) return;
_dataGridColumnsModel = value;
OnPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
结果:
更新
通过设置 AutoGenerateColumns="True"
并动态创建列,您将获得相同的结果。
关于c# - 在 DataGrid 中绑定(bind)自定义 header 控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49015253/
好的,所以我编辑了以下... 只需将以下内容放入我的 custom.css #rt-utility .rt-block {CODE HERE} 但是当我尝试改变... 与 #rt-sideslid
在表格 View 中,我有一个自定义单元格(在界面生成器中高度为 500)。在该单元格中,我有一个 Collection View ,我按 (10,10,10,10) 固定到边缘。但是在 tablev
对于我的无能,我很抱歉,但总的来说,我对 Cocoa、Swift 和面向对象编程还很陌生。我的主要来源是《Cocoa Programming for OS X》(第 5 版),以及 Apple 的充满
我正在使用 meta-tegra 为我的 NVIDIA Jetson Nano 构建自定义图像。我需要 PyTorch,但没有它的配方。我在设备上构建了 PyTorch,并将其打包到设备上的轮子中。现
在 jquery 中使用 $.POST 和 $.GET 时,有没有办法将自定义变量添加到 URL 并发送它们?我尝试了以下方法: $.ajax({type:"POST", url:"file.php?
Traefik 已经默认实现了很多中间件,可以满足大部分我们日常的需求,但是在实际工作中,用户仍然还是有自定义中间件的需求,为解决这个问题,官方推出了一个 Traefik Pilot[1] 的功
我想让我的 CustomTextInputLayout 将 Widget.MaterialComponents.TextInputLayout.OutlinedBox 作为默认样式,无需在 XML 中
我在 ~/.emacs 中有以下自定义函数: (defun xi-rgrep (term) (grep-compute-defaults) (interactive "sSearch Te
我有下表: 考虑到每个月的权重,我的目标是在 5 个月内分散 10,000 个单位。与 10,000 相邻的行是我最好的尝试(我在这上面花了几个小时)。黄色是我所追求的。 我试图用来计算的逻辑如下:计
我的表单中有一个字段,它是文件类型。当用户点击保存图标时,我想自然地将文件上传到服务器并将文件名保存在数据库中。我尝试通过回显文件名来测试它,但它似乎不起作用。另外,如何将文件名添加到数据库中?是在模
我有一个 python 脚本来发送电子邮件,它工作得很好,但问题是当我检查我的电子邮件收件箱时。 我希望该用户名是自定义用户名,而不是整个电子邮件地址。 最佳答案 发件人地址应该使用的格式是: You
我想减小 ggcorrplot 中标记的大小,并减少文本和绘图之间的空间。 library(ggcorrplot) data(mtcars) corr <- round(cor(mtcars), 1)
GTK+ noob 问题在这里: 是否可以自定义 GtkFileChooserButton 或 GtkFileChooserDialog 以删除“位置”部分(左侧)和顶部的“位置”输入框? 我实际上要
我正在尝试在主页上使用 ajax 在 magento 中使用 ajax 显示流行的产品列表,我可以为 5 或“N”个产品执行此操作,但我想要的是将分页工具栏与结果集一起添加. 这是我添加的以显示流行产
我正在尝试使用 PasswordResetForm 内置函数。 由于我想要自定义表单字段,因此我编写了自己的表单: class FpasswordForm(PasswordResetForm):
据我了解,新的 Angular 7 提供了拖放功能。我搜索了有关 DnD 的 Tree 组件,但没有找到与树相关的内容。 我在 Stackblitz 上找到的一个工作示例.对比drag'ndrop功能
我必须开发一个自定义选项卡控件并决定使用 WPF/XAML 创建它,因为我无论如何都打算学习它。完成后应该是这样的: 到目前为止,我取得了很好的进展,但还有两个问题: 只有第一个/最后一个标签项应该有
我要定制xtable用于导出到 LaTeX。我知道有些问题是关于 xtable在这里,但我找不到我要找的具体东西。 以下是我的表的外观示例: my.table <- data.frame(Specif
用ejs在这里显示日期 它给我结果 Tue Feb 02 2016 16:02:24 GMT+0530 (IST) 但是我需要表现为 19th January, 2016 如何在ejs中执行此操作?
我想问在 JavaFX 中使用自定义对象制作 ListView 的最佳方法,我想要一个每个项目如下所示的列表: 我搜了一下,发现大部分人都是用细胞工厂的方法来做的。有没有其他办法?例如使用客户 fxm
我是一名优秀的程序员,十分优秀!