将Cell中具有CustomClass的DataTable绑定到DataGrid WPF

问题描述 投票:0回答:1

我有数据网格。

    <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 中看到的 具有列过滤的自定义网格

wpf data-binding datatable datagrid
1个回答
0
投票

我不确定我是否正确理解了您的所有代码。我会根据我能理解的提供一个解决方案。
在数据表单元格中,您的类型为“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
                            }
                        );
                }
            }
        }

不幸的是,我无法测试这段代码。但如果您提供重现这些情况的最少代码,我可以进行测试并准备有保证的工作版本。

© www.soinside.com 2019 - 2024. All rights reserved.