我正在使用ContentControl来更改UI中显示的控件,具体取决于用户通过DataTemplateSelector选择的对象类型。
当控件被卸载时,基于替换下面ContentControl中的内容,我无法再访问 附加行为的Unloaded事件处理程序中附加行为的属性。
例如,如果用户点击钻孔单元然后单击UI中的Fuel Truck单元,则无法访问控件中的附加属性。它就像卸载控件时为时已晚,无法读取附加属性 当DateTemplateSelector触发时。
如果控件因为我关闭父窗口而被卸载,或者由于某些其他原因(如隐藏父文档选项卡)那么我 读取附加的行为属性值没有问题。
这是失败的代码片段:
代码试图找到附加的行为属性:"行为:PersistUiBehavior.PersistanceChildCode"从下面 我期待"结果"根据控件何时激活,等于17或18。
public static void GetPersistenceRequiredControls(DependencyProperty property, DependencyObject root, int code, List<object> sources)
{
if ((property != null) && (root != null))
{
// property = behaviours:PersistUiBehavior.PersistanceChildCode does not exist here when unloaded
var result = (int) root.GetValue(property);
if (result == code)
{
sources.Add(root);
}
}
}
这是一个显示各个部分的XAML片段:
<UserControl x:Class="FleetControl.Editors.Views.PropertyEditor">
<UserControl.Resources>
<ResourceDictionary>
<templates:PropertyEditorTemplateSelector x:Key="PropertyEditorTemplateSelector">
<templates:PropertyEditorTemplateSelector.DrillUnitEditorTemplate>
<DataTemplate>
<telerik:RadPropertyGrid
x:Name="DrillPropertyGrid"
behaviours:PersistUiBehavior.FileName="Test1.txt"
behaviours:PersistUiBehavior.PersistanceParentCode="5"
behaviours:PersistUiBehavior.PersistanceChildCode="17"
behaviours:PersistUiBehavior.Name="DrillPropertyGrid">
<telerik:RadPropertyGrid.PropertyDefinitions>
<telerik:PropertyDefinition DisplayName="Equipment Ident" Binding="{Binding DisplayName, Mode=OneWay}" GroupName="Description" IsReadOnly="True" />
<telerik:PropertyDefinition DisplayName="Equipment Description" Binding="{Binding Description, Mode=OneWay}" GroupName="Description" IsReadOnly="True"/>
<telerik:PropertyDefinition DisplayName="Equipment Type Ident" Binding="{Binding EquipmentType.Ident, Mode=OneWay}" GroupName="Description" IsReadOnly="True"/>
</telerik:RadPropertyGrid.PropertyDefinitions>
</telerik:RadPropertyGrid>
</DataTemplate>
</templates:PropertyEditorTemplateSelector.DrillUnitEditorTemplate>
<templates:PropertyEditorTemplateSelector.FuelTruckUnitEditorTemplate>
<DataTemplate>
<telerik:RadPropertyGrid
x:Name="FuelTruckUnitPropertyGrid"
behaviours:PersistUiBehavior.FileName="Test2.txt"
behaviours:PersistUiBehavior.PersistanceParentCode="6"
behaviours:PersistUiBehavior.PersistanceChildCode="18"
behaviours:PersistUiBehavior.Name="FuelTruckUnitPropertyGrid">
<telerik:RadPropertyGrid.PropertyDefinitions>
<telerik:PropertyDefinition DisplayName="Location" Binding="{Binding Location.LocationName, Mode=OneWay}" GroupName="Realtime" IsReadOnly="True"/>
<telerik:PropertyDefinition DisplayName="Location Code" Binding="{Binding Location.Code, Mode=OneWay}" GroupName="Realtime" IsReadOnly="True"/>
<telerik:PropertyDefinition DisplayName="Location Description" Binding="{Binding Location.Description, Mode=OneWay}" GroupName="Realtime" IsReadOnly="True"/>
</telerik:RadPropertyGrid.PropertyDefinitions>
</telerik:RadPropertyGrid>
</DataTemplate>
</templates:PropertyEditorTemplateSelector.FuelTruckUnitEditorTemplate>
</templates:PropertyEditorTemplateSelector>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ContentControl
ContentTemplateSelector="{StaticResource PropertyEditorTemplateSelector}"
Content="{Binding Path=SelectedPropertyEditor, Mode=OneWay}" />
</Grid>
</UserControl>
答案 0 :(得分:2)
是的,你是对的。当ContentPresenter
的模板发生更改时,将清除附加属性(实际上是所有属性)。这是System.Windows.StyleHelper.DoTemplateInvalidations()
方法执行的操作的一部分,在本例中由ContentPresenter.OnTemplateChanged()
方法调用。这最终会导致System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode()
被调用,这是实际工作的地方。
例如,这是我在调试器中看到的调用堆栈:
WindowsBase.dll!System.Windows.DependencyObject.InvalidateProperty(System.Windows.DependencyProperty dp, bool preserveCurrentValue) Unknown
PresentationFramework.dll!System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode(System.Windows.DependencyObject container, MS.Internal.FrameworkObject child, int childIndex, ref MS.Utility.FrugalStructList<System.Windows.ChildRecord> childRecordFromChildIndex, bool isDetach, System.Windows.FrameworkElementFactory templateRoot) Unknown
PresentationFramework.dll!System.Windows.StyleHelper.ClearTemplateChain(System.Collections.Specialized.HybridDictionary[] instanceData, System.Windows.FrameworkElement feContainer, System.Windows.FrameworkContentElement fceContainer, System.Collections.Generic.List<System.Windows.DependencyObject> templateChain, System.Windows.FrameworkTemplate oldFrameworkTemplate) Unknown
PresentationFramework.dll!System.Windows.StyleHelper.ClearGeneratedSubTree(System.Collections.Specialized.HybridDictionary[] instanceData, System.Windows.FrameworkElement feContainer, System.Windows.FrameworkContentElement fceContainer, System.Windows.FrameworkTemplate oldFrameworkTemplate) Unknown
PresentationFramework.dll!System.Windows.StyleHelper.DoTemplateInvalidations(System.Windows.FrameworkElement feContainer, System.Windows.FrameworkTemplate oldFrameworkTemplate) Unknown
PresentationFramework.dll!System.Windows.Controls.ContentPresenter.OnTemplateChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) Unknown
这一切都发生在调用Unloaded
事件之前。无论好坏,这完全是设计上的。
如果没有一个好的Minimal, Complete, and Verifiable example能清楚地显示您的代码所做的事情,以及对该代码最终目标的准确解释,我无法真正说出最佳替代方法会的。
至少有几个明显的解决方法可以想到,两者都涉及在Unloaded
事件处理程序中尝试执行的工作的某个时间点:
SelectedPropertyEditor
属性的更改。PropertyChangedCallback
委托并在那里进行工作(即当您看到附加属性从之前的某个值更改为null
时)。我会注意到,在您发布的一小段代码中,您似乎正在尝试依赖于模板本身中声明为的DependencyObject
(例如telerik:RadPropertyGrid
对象)。恕我直言,这可能会在其他地方引起其他问题。我承认,我并不确切地知道出了什么问题,但是在WPF已经卸载它之后尝试进入模板化的子图并复活它似乎是错误的。因此,即使您解决了属性失效问题,当您尝试重用该对象时,也可能会在以后遇到更多问题。
如果您需要更多具体的帮助,请发布一个新问题,其中您提供了一个很好的代码示例,以及有关模板时您希望发生的具体的确切详细信息卸载,以及您希望以后能够在卸载后使用模板化对象。