【发布时间】:2019-08-18 03:08:21
【问题描述】:
在我当前的 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 上方的按钮。如您所见,列已生成,但未显示行。我调试了代码,一切都在我的 ViewModel 中正确设置。当我选择第二个 ListItemModel 并返回第一个时,内容将正确显示。
你有什么想法吗?
【问题讨论】:
-
ColumnsBindingBehaviour的实现在哪里?第一个链接是错误的。 -
@mm8 对不起,我编辑了这个问题。谢谢你的建议。
标签: c# wpf data-binding