WinUI3/.NET9中更新ItemsSource后背景色绑定值异常
问题:ObservableCollection更新后自定义控件背景色绑定异常,其他属性正常
我通过数据模板绑定ObservableCollection中的值更新自定义控件背景色,但集合更新后背景色绑定获取错误值,其他属性更新正常。已尝试修改属性名称、属性变更时重新应用模板,均无效。
相关代码片段
CustomControls项目/Themes/Generic.xaml
<Style TargetType="local:CustomTableCard"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:CustomTableCard"> <Grid Height="300" Width="300" BorderThickness="4" Background="{Binding BackgroundColorProp, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay, FallbackValue='Black', TargetNullValue='Blue'}">
CustomControls项目/CustomTableCard.cs
public class CustomTableCard : Control { public static readonly DependencyProperty BackgroundColorProperty = DependencyProperty.Register( nameof(BackgroundColorProperty), typeof(string), typeof(CustomTableCard), new PropertyMetadata(null)); public string BackgroundColorProp { get => (string)GetValue(BackgroundColorProperty); set => SetValue(BackgroundColorProperty, value); } public CustomTableCard() { this.DefaultStyleKey = typeof(CustomTableCard); } protected override void OnApplyTemplate() { base.OnApplyTemplate(); [...] } }
View项目/CustomTablePage.xaml
<Page.Resources> <DataTemplate x:Key="CustomTableItemTemplateNew" x:DataType="Data:CustomTableCardData"> <ItemContainer> <customControls:CustomTableCard TableName="{x:Bind TableNameData, Mode=OneWay}" TextColor="{x:Bind TextColorData, Mode=OneWay}" [...] BackgroundColorProp="{x:Bind BackgroundColorData}" TableDeletionRequested="CustomTableItem_TableDeletionRequested" /> </ItemContainer> </DataTemplate> </Page.Resources> [...] <ItemsView x:Name="itemsViewTables" HorizontalAlignment="Stretch" ItemTemplate="{StaticResource CustomTableItemTemplateNew}" ItemsSource="{x:Bind Data:CustomTableCardDataRepository.customTableItemsCollection, Mode=OneWay}"
View项目/CustomTablePage.xaml.cs
public void loadTables() { CustomTableCardDataRepository.FillCustomTablesCollection((int)userId); itemsViewTables.ItemsSource = CustomTableCardDataRepository.customTableItemsCollection; }
异常现象
- 页面初始调用
loadTables()加载数据时显示正常,背景色符合预期。 - 未刷新页面,仅再次调用
loadTables()填充customTableItemsCollection(数据本身正确)后,新增表格背景色显示异常,颜色在控件间混乱。 - 切换页面再返回后,所有控件显示恢复正常。
- 偶尔所有按钮会显示错误的统一背景色,但调试时
CustomTableCard的属性值已正确设置为目标颜色,ItemsSource中的数据也完全正确。 - 重启应用并移除其他卡片后,单个按钮仍会出现背景色异常。
重要新信息
修改按钮默认颜色后,异常显示的颜色也同步改变;调试构造函数时,代码正确设置了目标颜色,并未执行设置为错误颜色的逻辑。推测控件可能复用了已移除控件的旧数据,绑定存在问题。
解决方案
1. 修正依赖属性注册错误
你的BackgroundColorProperty注册存在关键错误:注册名称参数用了nameof(BackgroundColorProperty),但实际对应的CLR属性是BackgroundColorProp,这会导致WPF/UWP依赖属性系统无法正确关联属性,绑定更新时无法通知UI刷新。
修正后的代码:
public static readonly DependencyProperty BackgroundColorPropProperty = DependencyProperty.Register( nameof(BackgroundColorProp), // 匹配CLR属性名 typeof(string), typeof(CustomTableCard), new PropertyMetadata(null, OnBackgroundColorPropChanged)); // 添加属性变更回调确保UI更新 public string BackgroundColorProp { get => (string)GetValue(BackgroundColorPropProperty); set => SetValue(BackgroundColorPropProperty, value); } // 可选:属性变更回调,强制刷新模板绑定 private static void OnBackgroundColorPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var control = d as CustomTableCard; control?.InvalidateVisual(); }
2. 确保数据模型实现INotifyPropertyChanged
检查CustomTableCardData类是否实现INotifyPropertyChanged接口,当BackgroundColorData变更时触发PropertyChanged事件,否则x:Bind无法感知数据更新。
示例实现:
public class CustomTableCardData : INotifyPropertyChanged { private string _backgroundColorData; public string BackgroundColorData { get => _backgroundColorData; set { if (_backgroundColorData != value) { _backgroundColorData = value; OnPropertyChanged(nameof(BackgroundColorData)); } } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // 其他属性同理实现 }
3. 避免重复设置ItemsSource
ObservableCollection本身支持集合变更通知,无需每次调用loadTables()都重新赋值ItemsSource,直接更新集合内容即可:
public void loadTables() { var newItems = CustomTableCardDataRepository.FillCustomTablesCollection((int)userId); // 清空现有集合并添加新项,保留原集合引用 CustomTableCardDataRepository.customTableItemsCollection.Clear(); foreach (var item in newItems) { CustomTableCardDataRepository.customTableItemsCollection.Add(item); } // 移除重复赋值:itemsViewTables.ItemsSource = ...; }
4. 清理控件复用状态
ItemsControl会复用控件容器,若控件未清理旧状态会导致值残留,可在CustomTableCard的Unloaded事件中清理背景色:
protected override void OnUnloaded(RoutedEventArgs e) { base.OnUnloaded(e); // 清理背景色,避免复用旧值 BackgroundColorProp = null; }
内容的提问来源于stack exchange,提问作者Arthur Buzas Baccan
相关产品推荐
相关产品推荐

