我有数据网格。
<DataGrid ItemsSource="{Binding DataView}" x:Name="AttributeGrid"
AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" EnableColumnVirtualization="False" EnableRowVirtualization="False"
DataContextChanged="AttributeGrid_DataContextChanged">
</DataGrid>
对于该 DataGrid 的单元格,我有自定义样式
<Style x:Key="DataGridDataViewCustomCellStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<Grid>
<ComboBox x:Name="ComboBoxCondition" IsEditable="True" ItemsSource="{Binding Values}" Visibility="Collapsed"
SelectedValue="{Binding SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="ValueID"
DisplayMemberPath="ValueStr"/>
<TextBox x:Name="TextBoxCondition" Text="{Binding TextValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="True" Visibility="Collapsed"/>
<DatePicker x:Name="DateCondition"
Text="{Binding DateValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="True" Visibility="Collapsed"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ValueType}" Value="Text">
<Setter Property="Visibility" TargetName="TextBoxCondition" Value="Visible"/>
<Setter Property="Visibility" TargetName="ComboBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="DateCondition" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding ValueType}" Value="Combobox">
<Setter Property="Visibility" TargetName="TextBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="ComboBoxCondition" Value="Visible"/>
<Setter Property="Visibility" TargetName="DateCondition" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding ValueType}" Value="Date">
<Setter Property="Visibility" TargetName="TextBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="ComboBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="DateCondition" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsModified, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="Background" TargetName="TextBoxCondition" Value="Cornsilk"/>
<Setter Property="Background" TargetName="ComboBoxCondition" Value="Cornsilk"/>
<Setter Property="Background" TargetName="DateCondition" Value="Cornsilk"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsModified, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Background" TargetName="TextBoxCondition" Value="White"/>
<Setter Property="Background" TargetName="ComboBoxCondition" Value="White"/>
<Setter Property="Background" TargetName="DateCondition" Value="White"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
如果 DataView 基于
List<object>
gridAttributes = new List<AttributeItem>();
gridAttributes add some data .....
DataView = CollectionViewSource.GetDefaultView(gridAttributes);
一切都按预期进行。在 DataGridCell 中,我有 AttributeIem 对象,并且可以根据需要设置其样式。
但是,当 DataView 基于 DataTable 时,然后在 DataGridCell 中,由于某种原因我得到了 DataRowView,然后 Style 不起作用,一切都出错了。
RunDataTable.Rows.Clear();
RunDataTable.Columns.Clear();
RunDataTable.Columns.Add("SectionName");
RunDataTable.Columns.Add("RunName");
foreach (AttributeItem attr in gridAttributes)
{
RunDataTable.Columns.Add(attr.AttributeName, typeof(AttributeItem));
}
DataRow row = RunDataTable.NewRow();
row["SectionName"] = section;
row["RunName"] = name;
foreach (AttributeItem item in gridAttributes)
{
row[item.AttributeName] = item;
}
RunDataTable.Rows.Add(row);
DataView = new DataView(RunDataTable);
这是我收到的错误绑定列表
System.Windows.Data Error: 40 : BindingExpression path error: 'IsModified' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=IsModified; DataItem='DataRowView' (HashCode=47477033); target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'Values' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=Values; DataItem='DataRowView' (HashCode=47477033); target element is 'ComboBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
System.Windows.Data Error: 40 : BindingExpression path error: 'SelectedValue' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=SelectedValue; DataItem='DataRowView' (HashCode=47477033); target element is 'ComboBox' (Name=''); target property is 'SelectedValue' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'TextValue' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=TextValue; DataItem='DataRowView' (HashCode=47477033); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'DateValue' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=DateValue; DataItem='DataRowView' (HashCode=47477033); target element is 'DatePicker' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'ValueType' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=ValueType; DataItem='DataRowView' (HashCode=47477033); target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'ValueType' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=ValueType; DataItem='DataRowView' (HashCode=47477033); target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'ValueType' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=ValueType; DataItem='DataRowView' (HashCode=47477033); target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'IsModified' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=IsModified; DataItem='DataRowView' (HashCode=47477033); target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'IsModified' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=IsModified; DataItem='DataRowView' (HashCode=47477033); target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'Values' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=Values; DataItem='DataRowView' (HashCode=47477033); target element is 'ComboBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
System.Windows.Data Error: 40 : BindingExpression path error: 'SelectedValue' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=SelectedValue; DataItem='DataRowView' (HashCode=47477033); target element is 'ComboBox' (Name=''); target property is 'SelectedValue' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'TextValue' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=TextValue; DataItem='DataRowView' (HashCode=47477033); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'DateValue' property not found on 'object' ''DataRowView' (HashCode=47477033)'. BindingExpression:Path=DateValue; DataItem='DataRowView' (HashCode=47477033); target element is 'DatePicker' (Name=''); target property is 'Text' (type 'String')
任何建议我如何调整我的样式或代码隐藏以使其正常工作。 谢谢。
我尝试了不同的数据源方式。但不幸的是每次我都会遇到同样的错误
添加列:
public static void RefreshColumnsFromModel(this DataGrid datagrid, DataGridRuns gridModel)
{
var myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source = new Uri("/SomeSource;component/Resources/SomeSource.xaml", UriKind.RelativeOrAbsolute);
datagrid.Columns.Clear();
foreach (ColumnWithFilter column in gridModel.Columns.OrderBy(c => c.Index))
{
if (column.IsReadOnly)
{
datagrid.Columns.Add(
new DataGridTextColumn()
{
Header = column.ColumnHeader,
IsReadOnly = column.IsReadOnly,
Binding = new Binding(column.ColumnBinding),
CellStyle = myResourceDictionary["DataGridReadOnlyCellStyle"] as Style,
HeaderTemplate = datagrid.Resources["HeaderTemplate"] as DataTemplate
}
);
}
else
{
datagrid.Columns.Add(
new DataGridTemplateColumn()
{
Header = column.ColumnHeader,
IsReadOnly = column.IsReadOnly,
//Binding = new Binding(column.ColumnBinding),
//HeaderTemplate = myResourceDictionary["HeaderTemplate"] as DataTemplate
HeaderTemplate = datagrid.Resources["HeaderTemplate"] as DataTemplate,
CellStyle = myResourceDictionary["DataGridDataViewCustomCellStyle"] as Style
}
);
}
}
}
DataGridRuns 代表 DataGrid 的模型,一些用于过滤和排序的自定义行为
public class DataGridRuns : BaseClass
{
private List<AttributeItem> gridAttributes = new List<AttributeItem>();
public ObservableCollection<AttributeItem> GridAttributes
{
get { return new ObservableCollection<AttributeItem>(gridAttributes); }
set { gridAttributes = value.ToList(); RaisePropertyChanged(); }
}
public DataTable RunDataTable { get; set; } = new DataTable("RunData");
private DataView dataView = null;
public DataView DataView
{
get { return dataView; }
}
private ColumnWithFilter selectedColumn = null;
public ColumnWithFilter SelectedColumn
{
get { return selectedColumn; }
set { selectedColumn = value; RaisePropertyChanged(); }
}
public Action RefreshColumns;
private List<ColumnWithFilter> columns = new List<ColumnWithFilter>();
public ObservableCollection<ColumnWithFilter> Columns
{
get { return new ObservableCollection<ColumnWithFilter>(columns); }
set { columns = value.ToList(); RaisePropertyChanged(); }
}
public DataGridRuns()
{
}
private List<AttributeItem> CreateAttributesFromInfo(IList<AttributeInfo> _attributes)
{
List<AttributeItem> result = new List<AttributeItem>();
try
{
foreach (var attr in _attributes)
{
result.Add(new AttributeItem(attr));
}
}
catch (Exception ex)
{
}
return result;
}
public void AddRun(string section, string name, IList<AttributeInfo> _attributes, bool template = false)
{
var attr = CreateAttributesFromInfo(_attributes);
if (gridAttributes == null || gridAttributes.Count() == 0)
{
gridAttributes = new List<AttributeItem>(attr);
CreateColumns();
}
DataRow row = RunDataTable.NewRow();
row["SectionName"] = section;
row["RunName"] = name;
foreach (AttributeItem item in gridAttributes)
{
row[item.AttributeName] = item;
}
RunDataTable.Rows.Add(row);
dataView = new DataView(RunDataTable);
//dataView = CollectionViewSource.GetDefaultView(RunDataTable);
}
public void ClearData()
{
gridAttributes.Clear();
gridAttributes = new List<AttributeItem>();
}
public void CreateColumns()
{
RunDataTable.Rows.Clear();
RunDataTable.Columns.Clear();
columns = new List<ColumnWithFilter>();
ColumnWithFilter col = null;
col = new ColumnWithFilter("Section Name", nameof(AttributeItem.SectionName))
{
Index = 0,
IsReadOnly = true,
};
columns.Add(col);
RunDataTable.Columns.Add("SectionName");
col = new ColumnWithFilter("Run Name", nameof(AttributeItem.RunName))
{
Index = 1,
IsReadOnly = true,
};
columns.Add(col);
RunDataTable.Columns.Add("RunName");
int colIndex = 1;
foreach (AttributeItem attr in gridAttributes)
{
col = new ColumnWithFilter(attr.AttributeName, nameof(attr))
{
Index = ++colIndex,
IsReadOnly = false,
};
columns.Add(col);
RunDataTable.Columns.Add(attr.AttributeName, typeof(AttributeItem));
}
}
public void RefreshDataView()
{
foreach (DataRow item in RunDataTable.Rows)
{
item.ItemArray.ToList().ForEach(a => (a as AttributeItem)?.StartMarkingModifications());
}
RaisePropertyChanged(nameof(DataView));
}
public void RefreshPopupContent(string header = "")
{
selectedColumn = columns.Where(c => c.ColumnHeader.Equals(header)).FirstOrDefault();
if (selectedColumn == null) return;
selectedColumn.RefreshFilterValues(gridAttributes
.Where(a => !string.IsNullOrEmpty((string)GetPropertyValue(a, selectedColumn.ColumnBinding)))
.Select(a => (string)GetPropertyValue(a, selectedColumn.ColumnBinding)).Distinct().ToList());
RaisePropertyChanged(nameof(SelectedColumn));
}
public void Filtering()
{
UpdateDataViewRowFilter();
}
private void UpdateDataViewRowFilter()
{
string rowFilter = string.Empty;
foreach (ColumnWithFilter column in columns.Where(c => c.FilterIndex > 0))
{
string andStr = !string.IsNullOrEmpty(rowFilter) ? " AND " : "";
switch (column.FilterIndex)
{
case 1:
rowFilter += andStr + $"{column.ColumnBinding} IS NULL";
break;
default:
rowFilter += andStr + $"{column.ColumnBinding} = '{column.FilteredValue}'";
//filterResult = ((string)GetPropertyValue(attribute, column.ColumnBinding)).Equals(column.FilteredValue);
break;
}
}
(dataView as DataView).RowFilter = rowFilter;
}
public object GetPropertyValue(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName)?.GetValue(obj, null);
}
}
这是我在 DataTable 中看到的,我希望在 DataGrid 中也能看到同样的结果 DataTable Visualizer 的屏幕截图
添加这是我在 UI 中看到的 具有列过滤的自定义网格
我不确定我是否正确理解了您的所有代码。我会根据我能理解的提供一个解决方案。
在数据表单元格中,您的类型为“AttributeItem”。具有路径“column.ColumnBinding”的绑定将从相应的单元格返回该类型的实例。 ValueType 和 IsModified 属性(在 ControlTemplate 中使用)属于此实例。
在这种情况下,我认为您错误地使用了 DataGridCell 样式更改。相反,您需要为单元格的内容创建一个数据模板。
<DataTemplate x:Key="DataGridDataViewCustomCellDataTemplate">
<Grid>
<ComboBox x:Name="ComboBoxCondition" IsEditable="True" ItemsSource="{Binding Values}" Visibility="Collapsed"
SelectedValue="{Binding SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="ValueID"
DisplayMemberPath="ValueStr"/>
<TextBox x:Name="TextBoxCondition" Text="{Binding TextValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="True" Visibility="Collapsed"/>
<DatePicker x:Name="DateCondition"
Text="{Binding DateValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="True" Visibility="Collapsed"/>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ValueType}" Value="Text">
<Setter Property="Visibility" TargetName="TextBoxCondition" Value="Visible"/>
<Setter Property="Visibility" TargetName="ComboBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="DateCondition" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding ValueType}" Value="Combobox">
<Setter Property="Visibility" TargetName="TextBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="ComboBoxCondition" Value="Visible"/>
<Setter Property="Visibility" TargetName="DateCondition" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding ValueType}" Value="Date">
<Setter Property="Visibility" TargetName="TextBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="ComboBoxCondition" Value="Hidden"/>
<Setter Property="Visibility" TargetName="DateCondition" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsModified, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="Background" TargetName="TextBoxCondition" Value="Cornsilk"/>
<Setter Property="Background" TargetName="ComboBoxCondition" Value="Cornsilk"/>
<Setter Property="Background" TargetName="DateCondition" Value="Cornsilk"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsModified, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Background" TargetName="TextBoxCondition" Value="White"/>
<Setter Property="Background" TargetName="ComboBoxCondition" Value="White"/>
<Setter Property="Background" TargetName="DateCondition" Value="White"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
在模板 DataGridTemplateColumn 中,您需要创建一个带有 ContentControl 的模板,该模板将接受 Content 属性中路径“column.ColumnBinding”的绑定以及上述 ContentTemplate 属性中的模板。
private const string templateString = @"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">
<ContentControl
Content=""{{Binding {0}}}""
ContentTemplate=""{{DynamicResource DataGridDataViewCustomCellDataTemplate}}""/>
</DataTemplate>
";
public static void RefreshColumnsFromModel(this DataGrid datagrid, DataGridRuns gridModel)
{
var myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source = new Uri("/SomeSource;component/Resources/SomeSource.xaml", UriKind.RelativeOrAbsolute);
datagrid.Columns.Clear();
foreach (ColumnWithFilter column in gridModel.Columns.OrderBy(c => c.Index))
{
if (column.IsReadOnly)
{
datagrid.Columns.Add(
new DataGridTextColumn()
{
Header = column.ColumnHeader,
IsReadOnly = column.IsReadOnly,
Binding = new Binding(column.ColumnBinding),
CellStyle = myResourceDictionary["DataGridReadOnlyCellStyle"] as Style,
HeaderTemplate = datagrid.Resources["HeaderTemplate"] as DataTemplate
}
);
}
else
{
string templateSource = string.Format(templateString, column.ColumnBinding);
var template = XamlReader.Parse(templateSource);
datagrid.Columns.Add(
new DataGridTemplateColumn()
{
Header = column.ColumnHeader,
IsReadOnly = column.IsReadOnly,
//Binding = new Binding(column.ColumnBinding),
//HeaderTemplate = myResourceDictionary["HeaderTemplate"] as DataTemplate
HeaderTemplate = datagrid.Resources["HeaderTemplate"] as DataTemplate,
CellStyle = myResourceDictionary["DataGridDataViewCustomCellStyle"] as Style
}
);
}
}
}
不幸的是,我无法测试这段代码。但如果您提供重现这些情况的最少代码,我可以进行测试并准备有保证的工作版本。