卸载控件时无法获取附加的行为属性值

时间:2016-02-01 21:48:48

标签: c# wpf xaml

我正在使用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>

1 个答案:

答案 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已经卸载它之后尝试进入模板化的子图并复活它似乎是错误的。因此,即使您解决了属性失效问题,当您尝试重用该对象时,也可能会在以后遇到更多问题。


如果您需要更多具体的帮助,请发布一个新问题,其中您提供了一个很好的代码示例,以及有关模板时您希望发生的具体的确切详细信息卸载,以及您希望以后能够在卸载后使用模板化对象。