C# 当动态生成列时,如何修复DataGrid中缺少的行显示?

C# 当动态生成列时,如何修复DataGrid中缺少的行显示?,c#,wpf,data-binding,C#,Wpf,Data Binding,在我当前的WPF应用程序中,需要在我的ViewModel中动态生成DataGrid的列。为此,我使用了System.Windows.Interactive和Behavior的方法。 因此,我创建了ColumnsBehavior,与本文完全相同: 当我初始化有界列表并使用绑定生成列时,一切都很好。 当我切换到ListBox在每个ListBoxItem中显示DataGrid时,一切又恢复了正常。 现在,我想在运行时将信息(模型)添加到有界列表中。 选择ListBoxItem时,应显示相应的Data

在我当前的WPF应用程序中,需要在我的ViewModel中动态生成DataGrid的列。为此,我使用了System.Windows.Interactive和Behavior的方法。 因此,我创建了ColumnsBehavior,与本文完全相同:

当我初始化有界列表并使用绑定生成列时,一切都很好。 当我切换到ListBox在每个ListBoxItem中显示DataGrid时,一切又恢复了正常。 现在,我想在运行时将信息(模型)添加到有界列表中。 选择ListBoxItem时,应显示相应的DataGrid。通过DataGrid上方的按钮,我可以将样本数据传递给有界列表对象。当我点击按钮时,会生成具有正确标题的适当数量的列,但行只会在下次显示,其中ListBoxItem再次可见。这意味着数据是在我刷新网格时出现的

要将Botton命令属性绑定到ViewModel,我使用了ActionCommand实现:

我使用的是MVVM模式

这是我的视图模型:

    public class ViewModel
    {
        public ViewModel()
        {
            ListItems = new ObservableCollection<ListItemModel>();
            ListItems.Add(new ListItemModel()
            {
                IsSelected = true
            });
            ListItems.Add(new ListItemModel()
            {
                IsSelected = false
            });

            FillCommand = new RelayCommand(FillAction);
        }

        public ObservableCollection<ListItemModel> ListItems { get; set; }

        public ListItemModel SelectedListItem { get; set; }

        public ICommand FillCommand { get; set; }

        public void FillAction(object sender)
        {
            SelectedListItem.Entries = new ObservableCollection<Entry>()
            {
                new Entry()
                {
                    Cells = new ObservableCollection<Cell>()
                    {
                        new Cell() { Cond1 = 11, Value = 99 },
                        new Cell() { Cond1 = 22, Value = 99 },
                        new Cell() { Cond1 = 33, Value = 99 }
                    }
                },
                new Entry()
                {
                    Cells = new ObservableCollection<Cell>()
                    {
                        new Cell() { Cond1 = 11, Value = 99 },
                        new Cell() { Cond1 = 22, Value = 99 },
                        new Cell() { Cond1 = 33, Value = 99 }
                    },
                },
                new Entry()
                {
                    Cells = new ObservableCollection<Cell>()
                    {
                        new Cell() { Cond1 = 11, Value = 99 },
                        new Cell() { Cond1 = 22, Value = 99 },
                        new Cell() { Cond1 = 33, Value = 99 }
                    },
                }
            };

            SelectedListItem.GenerateGrid();
        }
    }
下面的代码示例显示了该视图

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <ListBox ItemsSource="{Binding ListItems}" SelectedItem="{Binding SelectedListItem}">
            <ListBox.Resources>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                </Style>
            </ListBox.Resources>
        </ListBox>
        <DockPanel Grid.Column="1">
            <Button DockPanel.Dock="Top" Command="{Binding FillCommand}">Fill Data</Button>
            <DataGrid x:Name="ToleranceGrid" ColumnWidth="*" ItemsSource="{Binding Path=SelectedListItem.Entries}"
                      CanUserAddRows="False" SelectionMode="Single" SelectionUnit="Cell" AutoGenerateColumns="False" local:ColumnsBindingBehaviour.BindableColumns="{Binding Path=SelectedListItem.DataColumns}">
            </DataGrid>
        </DockPanel>
    </Grid>

填充数据
ViewModel设置为代码隐藏中视图的DataContext

结果应该如下所示:

选择了第一个ListItemModel,我按下了DataGrid上方的按钮。如您所见,已生成列,但未显示行。我调试了代码,在我的ViewModel中正确设置了一切。当我选择第二个ListItemModel并返回第一个ListItemModel时,内容将正确显示


您有什么想法吗?

条目
属性设置为新集合时,您的
列表项模型
应实现该接口并引发
属性更改
事件:

public class ListItemModel : INotifyPropertyChanged
{
    public ListItemModel()
    {
        Entries = new ObservableCollection<Entry>();
        DataColumns = new ObservableCollection<DataGridColumn>();
    }

    private ObservableCollection<Entry> _entries;
    public ObservableCollection<Entry> Entries
    {
        get { return _entries; }
        set { _entries = value; NotifyPropertyChanged(); }
    }

    public ObservableCollection<DataGridColumn> DataColumns { get; set; }

    public bool IsSelected { get; set; }

    public void GenerateGrid()
    {
        if (Entries.Count != 0)
        {
            var columns = Entries[0]?.Cells;

            for (int i = 0; i < columns.Count; i++)
            {
                Binding b = new Binding(string.Format("Cells[{0}].Value", i));
                DataGridTextColumn text = new DataGridTextColumn();
                text.Header = columns[i].Cond1.ToString();
                text.Binding = b;
                DataColumns.Add(text);
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
公共类ListItemModel:INotifyPropertyChanged
{
公共ListItemModel()
{
条目=新的ObservableCollection();
DataColumns=新的ObservableCollection();
}
私人可观察到的收集项目;
公共可观测收集条目
{
获取{return\u entries;}
设置{u entries=value;NotifyPropertyChanged();}
}
公共ObservableCollection数据列{get;set;}
公共布尔值被选为{get;set;}
public void GenerateGrid()
{
如果(Entries.Count!=0)
{
变量列=条目[0]?.单元格;
for(int i=0;i
条目
属性设置为新集合时,您的
列表项模型
应实现该接口并引发
属性更改
事件:

public class ListItemModel : INotifyPropertyChanged
{
    public ListItemModel()
    {
        Entries = new ObservableCollection<Entry>();
        DataColumns = new ObservableCollection<DataGridColumn>();
    }

    private ObservableCollection<Entry> _entries;
    public ObservableCollection<Entry> Entries
    {
        get { return _entries; }
        set { _entries = value; NotifyPropertyChanged(); }
    }

    public ObservableCollection<DataGridColumn> DataColumns { get; set; }

    public bool IsSelected { get; set; }

    public void GenerateGrid()
    {
        if (Entries.Count != 0)
        {
            var columns = Entries[0]?.Cells;

            for (int i = 0; i < columns.Count; i++)
            {
                Binding b = new Binding(string.Format("Cells[{0}].Value", i));
                DataGridTextColumn text = new DataGridTextColumn();
                text.Header = columns[i].Cond1.ToString();
                text.Binding = b;
                DataColumns.Add(text);
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
公共类ListItemModel:INotifyPropertyChanged
{
公共ListItemModel()
{
条目=新的ObservableCollection();
DataColumns=新的ObservableCollection();
}
私人可观察到的收集项目;
公共可观测收集条目
{
获取{return\u entries;}
设置{u entries=value;NotifyPropertyChanged();}
}
公共ObservableCollection数据列{get;set;}
公共布尔值被选为{get;set;}
public void GenerateGrid()
{
如果(Entries.Count!=0)
{
变量列=条目[0]?.单元格;
for(int i=0;i
列BindingBehavior的实现在哪里?第一个链接错误。@mm8对不起,我编辑了这个问题。谢谢您的建议。
列BindingBehavior
的实现在哪里?第一个链接错误。@mm8对不起,我编辑了这个问题。谢谢你的建议。我提供了一个非常小的示例,在我的实际代码中,属性要嵌套得多。我必须在链中的每个Setter中激活property,并将其更改为表示属性的行。非常感谢,这花了我将近一周的时间:)我提供了一个非常小的示例,在我的实际代码中,属性要嵌套得多。我必须在链中的每个Setter中激活property,并将其更改为表示属性的行。非常感谢,这花了我将近一周的时间:)
public class ListItemModel : INotifyPropertyChanged
{
    public ListItemModel()
    {
        Entries = new ObservableCollection<Entry>();
        DataColumns = new ObservableCollection<DataGridColumn>();
    }

    private ObservableCollection<Entry> _entries;
    public ObservableCollection<Entry> Entries
    {
        get { return _entries; }
        set { _entries = value; NotifyPropertyChanged(); }
    }

    public ObservableCollection<DataGridColumn> DataColumns { get; set; }

    public bool IsSelected { get; set; }

    public void GenerateGrid()
    {
        if (Entries.Count != 0)
        {
            var columns = Entries[0]?.Cells;

            for (int i = 0; i < columns.Count; i++)
            {
                Binding b = new Binding(string.Format("Cells[{0}].Value", i));
                DataGridTextColumn text = new DataGridTextColumn();
                text.Header = columns[i].Cond1.ToString();
                text.Binding = b;
                DataColumns.Add(text);
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}