调用NavigationView.ClearValue清除MenuItemsProperty时始终抛出ArgumentException
var temp = new NavigationView(); temp.ClearValue(NavigationView.MenuItemsProperty); // System.ArgumentException: 'Value does not fall within the expected range.' // Exception occurred: 'System.ArgumentException'(WinRT.Runtime.dll) // WinRT Infomation: Argument 'source' is null.
即便调用temp.ReadLocalValue(NavigationView.MenuItemsProperty)未返回DependencyProperty.UnsetValue,仍会抛出相同异常。
如何在调用SetBinding前实现与ClearValue相同的效果?
补充内容
private record BindingInfo(FrameworkElement Target, DependencyProperty TargetDp, string Path); private ImmutableDictionary<DependencyProperty, BindingInfo> _bindingInfos; private void SetBindingIfValueIsSet(DependencyProperty sourceDp) { if (ReadLocalValue(sourceDp) == DependencyProperty.UnsetValue) return; var (target, targetDp, path) = _bindingInfos[sourceDp]; // target.ClearValue(targetDp); target.SetBinding(targetDp, new Binding { Source = this, Path = new(path), Mode = BindingMode.OneWay, }); }
上述代码中,targetDp可以是任意依赖属性,例如NavigationView.MenuItemsProperty和Panel.BackgroundProperty。
我使用MenuItemsProperty而非MenuItemsSourceProperty,因为我是在XAML中直接创建NavigationViewItems的。
对于这种无法用ClearValue处理的特殊情况,单独做分支处理是否是最优方案?
解决方案
- 针对NavigationView.MenuItemsProperty的特殊处理
由于MenuItemsProperty是WinRT控件的集合属性,内部实现逻辑导致直接调用ClearValue会抛出异常,你可以通过清空集合来达到类似ClearValue的效果:
if (target is NavigationView navView && targetDp == NavigationView.MenuItemsProperty) { navView.MenuItems.Clear(); } else { target.ClearValue(targetDp); }
这样既清除了本地手动添加的菜单项,又避免了异常抛出。
替代ClearValue的通用逻辑
如果只是为了设置新绑定,其实新绑定会自动覆盖原有绑定或本地值,但对于你这种在XAML中手动创建NavigationViewItems的场景,直接设置绑定不会清空已有集合,所以必须先手动清空集合再绑定。特殊分支处理的合理性
这种针对特定属性的分支处理是合理且高效的。不同依赖属性的内部实现差异很大,尤其是WinRT控件属性和WPF原生属性的实现逻辑存在区别,单独处理能避免通用方法的异常,同时保证逻辑正确性。
内容的提问来源于stack exchange,提问作者appletree5641
相关产品推荐
相关产品推荐

