如何刷新DataTemplate内的DataGrid以更新绑定
我的DataGrid绑定的属性并非Observable类型,这是故意设计的——底层模型数据会在特定时机更新,我需要用户点击「Refresh」按钮手动触发DataGrid视图更新。
我已经给Refresh按钮绑定了命令,在ViewModel里执行:
CollectionViewSource.GetDefaultView(Units).Refresh();
这段代码似乎更新了底层视图数据,但DataGrid的UI并没有立刻刷新。奇怪的是,点击Refresh按钮后只要点一下DataGrid的任意区域,它就会重绘并显示最新数据。我怀疑是因为DataGrid放在DataTemplate里导致的,求解决办法。
相关XAML代码:
<TabControl ItemsSource="{Binding Units}" IsSynchronizedWithCurrentItem="True" TabContent.IsCached="True"> <TabControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Key, Mode=OneWay}"/> </DataTemplate> </TabControl.ItemTemplate> <TabContent.Template> <DataTemplate> <DockPanel Margin="5"> <DockPanel DockPanel.Dock="Top"> <WrapPanel> <Button Command="{Binding DataContext.Refresh, ElementName=Window}" CommandParameter="{Binding}">Refresh</Button> </WrapPanel> </DockPanel> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="5"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <DockPanel Grid.Row="0"> <Label DockPanel.Dock="Top" FontWeight="Bold">Items</Label> <DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" IsReadOnly="True"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Key}" Header="Name"/> <DataGridTextColumn Binding="{Binding Value}" Header="Value"/> <DataGridTextColumn Binding="{Binding Value.RV}" Header="RV"/>
解决方案
方法1:刷新对应Item的CollectionView
你当前刷新的是Units的视图,但DataGrid绑定的是每个Unit的Items集合。应该针对当前选中的Unit的Items视图执行刷新:
在Refresh命令的执行方法里,拿到CommandParameter传递过来的当前Unit实例,然后刷新它的Items视图:
var unit = commandParameter as YourUnitType; if (unit != null) { CollectionViewSource.GetDefaultView(unit.Items).Refresh(); }
方法2:强制DataGrid绑定更新
如果方法1没用,可以通过触发绑定的更新来强制UI刷新。可以在命令里找到当前DataGrid实例,手动更新绑定:
// 假设你能拿到当前的DataGrid实例 dataGrid.GetBindingExpression(DataGrid.ItemsSourceProperty)?.UpdateTarget();
如果不想在ViewModel里直接操作视图,可以用附加属性或者Messenger通知视图层执行这个操作。
方法3:关闭TabContent缓存
你的TabControl设置了TabContent.IsCached="True",缓存的Content可能不会响应视图刷新。尝试把这个属性设为False:
<TabControl ItemsSource="{Binding Units}" IsSynchronizedWithCurrentItem="True" TabContent.IsCached="False">
方法4:替换Items集合引用
如果Items是普通List而非ObservableCollection,可以在刷新时重新赋值一个新的集合实例,让绑定自动检测到变化:
var unit = commandParameter as YourUnitType; if (unit != null) { // 假设更新后的数据已经在unit.Items里,重新包装成新集合 var updatedItems = new List<YourItemType>(unit.Items); unit.Items = updatedItems; }
注意:这种方法需要Items所在的Unit类实现INotifyPropertyChanged接口,否则视图不会感知到属性变化。
内容的提问来源于stack exchange,提问作者neo

