在我当前的WPF应用程序中,需要在ViewModel中动态生成DataGrid的列。为此,我在System.Windows.Interactivity和行为中使用了该方法。 因此,我完全按照这篇文章创建了ColumnsBehavior:
Is it possible to get dynamic columns on wpf datagrid in mvvm pattern?
当我初始化绑定列表并生成带有绑定的列时,一切工作正常。 当我切换到ListBox以在每个ListBoxItem中显示一个DataGrid时,一切都再次正常运行。 现在,我想在运行时将信息(模型)添加到边界列表中。 选择ListBoxItem时,应显示相应的DataGrid。使用DataGrid上方的按钮,我可以将示例数据传递到边界列表对象。当我按下Button时,会生成正确数量的带有正确标题的列,但是该行仅在下一次出现时再次出现,其中ListBoxItem再次可见。这意味着数据是在刷新网格时出现的。
要将Botton Command属性绑定到ViewModel,我使用了ActionCommand实现:
我正在使用MVVM模式。
这是我的 ViewModel :
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();
}
}
用于保留列的属性在ListItemModel中。 在下面的代码中可以看到DataGrid的ItemsSource背后的对象结构和columns属性:
public class ListItemModel
{
public ListItemModel()
{
Entries = new ObservableCollection<Entry>();
DataColumns = new ObservableCollection<DataGridColumn>();
}
public ObservableCollection<Entry> Entries { get; set; }
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 class Entry
{
public ObservableCollection<Cell> Cells { get; set; }
public Entry() { Cells = new ObservableCollection<Cell>(); }
}
public class Cell
{
public Cell() { }
public int Cond1 { get; set; }
public int Value { get; set; }
}
}
对于视图,您需要名称空间:
http://schemas.microsoft.com/expression/2010/interactivity
以下代码示例显示了视图。
<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。
结果应如下所示: WPF Application
选择第一个ListItemModel,然后按下DataGrid上方的Button。如您所见,列已生成,但未显示行。我调试了代码,在ViewModel中正确设置了所有内容。当我选择第二个ListItemModel并返回到第一个时,内容将正确显示。
您有什么想法吗?
答案 0 :(得分:0)
当ListItemModel
属性设置为新集合时,您的PropertyChanged
应该实现INotifyPropertyChanged接口并引发Entries
事件:
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));
}
}