C# 如何基于绑定属性动态更改ContentTemplate?
我有一个问题困扰了我一段时间,但我相信我最终找到了它。症状是,当绑定属性之一触发交换C# 如何基于绑定属性动态更改ContentTemplate?,c#,wpf,C#,Wpf,我有一个问题困扰了我一段时间,但我相信我最终找到了它。症状是,当绑定属性之一触发交换ContentTemplate的DataTrigger时,WPF控件将无法正确呈现。堆栈跟踪: System.ArgumentNullException: Value cannot be null. Parameter name: d at MS.Internal.Data.ElementObjectRef.GetObject(DependencyObject d, ObjectRefArgs
ContentTemplate
的DataTrigger
时,WPF控件将无法正确呈现。堆栈跟踪:
System.ArgumentNullException: Value cannot be null.
Parameter name: d
at MS.Internal.Data.ElementObjectRef.GetObject(DependencyObject d, ObjectRefArgs args)
at MS.Internal.Data.ObjectRef.GetDataObject(DependencyObject d, ObjectRefArgs args)
at System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.VerifySourceReference(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Run(Object arg)
at MS.Internal.Data.DataBindEngine.OnLayoutUpdated(Object sender, EventArgs e)
at System.Windows.ContextLayoutManager.fireLayoutUpdateEvent()
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
at System.Windows.Media.MediaContext.InvokeOnRenderCallback.DoWork()
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
调试器根本没有帮助,因为它只是在application.Run()上中断。以下是我在实际xaml方面所做的工作:
<CollectionViewSource x:Key="SomeCollectionView"
Source="{Binding StatsByUser}"
IsLiveSortingRequested="True">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Amount" Direction="Descending"/>
<scm:SortDescription PropertyName="Name" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<ItemsControl Background="Transparent" Width="{StaticResource Width}"
ItemsSource="{Binding Source={StaticResource SomeCollectionView}}">
<ItemsControl.Resources>
<DataTemplate x:Key="FullViewTemplate">
<Border Style="{StaticResource BorderStyle}">
<controls:FullCustomEntityControl CustomEntityObject="{Binding}"
Style="{StaticResource PanelStyle}"
MouseDown="Info_OnMouseDown"/>
</Border>
</DataTemplate>
<DataTemplate x:Key="CompactViewTemplate">
<Border Style="{StaticResource BorderStyle}">
<controls:CompactCustomEntityControl CustomEntityObject="{Binding}"
Style="{StaticResource PanelStyle}"
MouseDown="Info_OnMouseDown"/>
</Border>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource FullViewTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=c:ShellView}, Path=ViewModel.ShowCompactView}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource CompactViewTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
每当ViewModel.showcomactview
引发PropertyChanged
事件并启动DataTrigger
时,它将切换ContentTemplate
,然后引发此错误。有没有一种方法可以解决这个问题,或者有更好的方法来设计ContentTemplate
交换,而这不会导致这个问题
编辑:可能相关的支持文章
Edit2:UI发生了什么的示例:。您可以看到大插槽是FullCustomEntityControl
,小插槽是CompactCustomEntityControl
。将它们保留在任一模式而不更改不会导致任何问题,但让数据触发器更改它们会导致类似这样的问题。此外,所使用的控件应该是一致的,而不是这里看起来像分裂的控件。通过让它们处于任一模式,我的意思是移除数据触发器并选择其中一个
Edit3:一篇关于类似问题的帖子,有来自Microsoft的人回应:
有关资料:
如果堆栈上的ArgumentNullException带有VerifySourceReference,那么它肯定是由Connect 561752中描述的问题引起的。即使你的应用程序没有直接使用ElementName绑定,它也可能间接使用它们——一些内置控件使用ElementName绑定:ComboBox、ContextMenu、MenuItem等
每个ItemsControl都有属性,您可以利用它。我不知道我是否理解错了问题,但当我将代码复制到解决方案时,它工作得非常好。下面是找我的零钱
我做的一件事是,将Path=ViewModel.ShowCompactView替换为Path=DataContext.ShowCompactView,relativesource是我的主窗口
<ItemsControl Background="Transparent"
ItemsSource="{Binding Source={StaticResource SomeCollectionView}}">
<ItemsControl.Resources>
<DataTemplate x:Key="FullViewTemplate">
<Border >
<Label Content="{Binding}"
/>
</Border>
</DataTemplate>
<DataTemplate x:Key="CompactViewTemplate">
<Border >
<Button Content="{Binding}"
/>
</Border>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource FullViewTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.ShowCompactView}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource CompactViewTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我对您的设置进行了修改,似乎一切正常。错误似乎与您的CompactCustomEntityControl
/FullCustomEntityControl
与PresentationCore交互时执行的操作有关
尝试在调试->选项中启用.NET Framework源代码单步执行以查看发生了什么:
据我所知,ItemTemplateSelector
只执行一次选择。在我的示例中,当绑定变量发生变化时,模板会得到更新。我很好奇,使用两个带有可见性绑定的ItemsControl
是否有效。即使控件不可见,也会有额外的处理开销吗?更改ContentTemplate
是解决此问题的可靠方法,并且不会导致ArgumentNullException
。问题可能来自您的控件CompactCustomEntityControl
和FullCustomEntityControl
。您可以获得异常在VS debug中引发的实际位置。我尝试用简化的示例(删除了自定义控件、CollectionViewSource等)重新创建您的问题,并且一切似乎都正常-它确实将我的TextBox模板与我的TextBlock模板切换。。。我建议您尝试创建一个简单的示例,并从中添加缺少的部分,直到找到真正的根cause@AmittaiShapira您要绑定到的集合中有多少个元素?当问题发生时,所发生的情况是,它中断的控件只是在正常情况下显示为空白。集合中其他确实绑定正确的元素没有出现问题。我还添加了一个可能相关的支持链接,似乎相关,但我怀疑这是原因,因为我的版本是18402,而修补程序版本是395。不幸的是,那个dll不再可以下载,所以我没有真正的方法来测试它是否是一个回归问题;但是,在某些情况下,会发生我提到的情况,而不是完全呈现控件,控件所在的位置只有空白。设置所有这些选项,使用Microsoft Symbol server,仍然没有可用的源。不确定在框架本身内调试会有多大帮助。@Lunyx尝试在选项->调试->符号作为源添加中关闭默认的“Microsoft符号服务器”。打开.net framework调试可能会有点麻烦,因为mscorlib版本通常与“Microsoft Symbol Servers”源代码版本不匹配,但我认为在您的情况下,这可能会有所帮助-您应该看到抛出的确切代码。以我的经验来看