locked
DataContext is set twice RRS feed

  • Question

  • Hi

    If I register to the DataContextChanged event of my user control it gets called twice even though I set the DataContext (DC) just once! If I check the new DC in the event handler, I see that at first the DC is set as expected (to my VM) but subsequently set back to NULL!

    Looking at the Call Stack it seems like the DC is set back from somewhere within the .NET Framework... Is this even possible?

    I attached the two Call Stacks:

    --> In this Call Stack my DC is set back to NULL:

    DataContextChanged-event of my User Control is called PresentationFramework.dll!System.Windows.FrameworkElement.RaiseDependencyPropertyChanged(System.Windows.EventPrivateKey key, System.Windows.DependencyPropertyChangedEventArgs args) Line 5723 + 0x30 bytes C# PresentationFramework.dll!System.Windows.FrameworkElement.OnDataContextChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) Line 2702 C# WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Line 1840 + 0x27 bytes C# PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Line 2069 + 0x22 bytes C# WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) Line 1553 + 0x1e bytes C# WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex = {System.Windows.EntryIndex}, System.Windows.DependencyProperty dp = {DataContext}, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry = {System.Windows.EffectiveValueEntry}, bool coerceWithDeferredReference, System.Windows.OperationType operationType) Line 1374 + 0x90 bytes C# //above here everything is the same PresentationFramework.dll!System.Windows.StyleHelper.ApplyTemplatedParentValue(System.Windows.DependencyObject container, MS.Internal.FrameworkObject child, int childIndex, ref MS.Utility.FrugalStructList<System.Windows.ChildRecord> childRecordFromChildIndex, System.Windows.DependencyProperty dp, System.Windows.FrameworkElementFactory templateRoot) Line 4463 C# PresentationFramework.dll!System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode(System.Windows.DependencyObject container = {System.Windows.Controls.ContentPresenter}, MS.Internal.FrameworkObject child, int childIndex = 1, ref MS.Utility.FrugalStructList<System.Windows.ChildRecord> childRecordFromChildIndex = {MS.Utility.FrugalStructList<System.Windows.ChildRecord>}, bool isDetach = false, System.Windows.FrameworkElementFactory templateRoot = null) Line 4916 + 0x5c bytes C# PresentationFramework.dll!System.Windows.StyleHelper.LoadOptimizedTemplateContent(System.Windows.DependencyObject container = {System.Windows.Controls.ContentPresenter}, System.Windows.Markup.ParserContext parserContext = {System.Windows.Markup.ParserContext}, System.Windows.Markup.OptimizedTemplateContent optimizedTemplateContent, System.Windows.FrameworkTemplate frameworkTemplate = {System.Windows.DataTemplate}, System.Windows.Markup.IComponentConnector componentConnector, System.Windows.Markup.IStyleConnector styleConnector, System.Collections.Generic.List<System.Windows.DependencyObject> affectedChildren, System.Windows.UncommonField<System.Collections.Hashtable> templatedNonFeChildrenField) Line 5274 C# //now the two Call Stack diverge //this line contains the first difference ("Line 5274" at the end) PresentationFramework.dll!System.Windows.FrameworkTemplate.LoadContent(System.Windows.DependencyObject container, System.Collections.Generic.List<System.Windows.DependencyObject> affectedChildren, System.Windows.UncommonField<System.Collections.Hashtable> templatedNonFeChildrenField) Line 546 + 0x18 bytes C# //removed deeper stack entries --> In this Call Stack my DC is set to my ViewModel:

    DataContextChanged-event of my User Control is called PresentationFramework.dll!System.Windows.FrameworkElement.RaiseDependencyPropertyChanged(System.Windows.EventPrivateKey key, System.Windows.DependencyPropertyChangedEventArgs args) Line 5723 + 0x30 bytes C# PresentationFramework.dll!System.Windows.FrameworkElement.OnDataContextChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) Line 2702 C# WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Line 1840 + 0x27 bytes C# PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Line 2069 + 0x22 bytes C# WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) Line 1553 + 0x1e bytes C# WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex = {System.Windows.EntryIndex}, System.Windows.DependencyProperty dp = {DataContext}, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry = {System.Windows.EffectiveValueEntry}, bool coerceWithDeferredReference, System.Windows.OperationType operationType) Line 1374 + 0x90 bytes C# //above here everything is the same PresentationFramework.dll!System.Windows.TreeWalkHelper.InvalidateTreeDependentProperty(System.Windows.TreeChangeInfo info, System.Windows.DependencyObject d, ref MS.Internal.FrameworkObject fo, System.Windows.DependencyProperty dp, System.Windows.FrameworkPropertyMetadata fMetadata, System.Windows.Style selfStyle, System.Windows.Style selfThemeStyle, ref System.Windows.ChildRecord childRecord, bool isChildRecordValid, bool hasStyleChanged, bool isSelfInheritanceParent) Line 356 + 0x105 bytes C# PresentationFramework.dll!System.Windows.TreeWalkHelper.InvalidateTreeDependentProperties(System.Windows.TreeChangeInfo info, System.Windows.FrameworkElement fe, System.Windows.FrameworkContentElement fce, System.Windows.Style selfStyle = null, System.Windows.Style selfThemeStyle = {System.Windows.Style}, ref System.Windows.ChildRecord childRecord = {System.Windows.ChildRecord}, bool isChildRecordValid = true, bool hasStyleChanged = false, bool isSelfInheritanceParent = true) Line 286 C# PresentationFramework.dll!System.Windows.FrameworkElement.InvalidateTreeDependentProperties(System.Windows.TreeChangeInfo parentTreeState, bool isSelfInheritanceParent) Line 530 + 0x31 bytes C# PresentationFramework.dll!System.Windows.FrameworkElement.OnAncestorChangedInternal(System.Windows.TreeChangeInfo parentTreeState) Line 415 + 0x1d bytes C# PresentationFramework.dll!System.Windows.TreeWalkHelper.OnAncestorChanged(System.Windows.FrameworkElement fe, System.Windows.FrameworkContentElement fce, System.Windows.TreeChangeInfo info) Line 201 + 0xffffffdf bytes C# PresentationFramework.dll!System.Windows.TreeWalkHelper.OnAncestorChanged(System.Windows.DependencyObject d, System.Windows.TreeChangeInfo info) Line 174 C# PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.StartWalk(System.Windows.DependencyObject startNode, bool skipStartNode) Line 59 + 0x26 bytes C# PresentationFramework.dll!MS.Internal.PrePostDescendentsWalker<System.Windows.TreeChangeInfo>.StartWalk(System.Windows.DependencyObject startNode = {Siemens.Gms.ClientCore.WPF.UserControls.BoolRenderer}, bool skipStartNode = false) Line 69 + 0xa bytes C# PresentationFramework.dll!System.Windows.TreeWalkHelper.InvalidateOnTreeChange(System.Windows.FrameworkElement fe, System.Windows.FrameworkContentElement fce, System.Windows.DependencyObject parent, bool isAddOperation) Line 135 + 0xf bytes C# PresentationFramework.dll!System.Windows.FrameworkElement.OnVisualParentChanged(System.Windows.DependencyObject oldParent = null) Line 2472 + 0x13 bytes C# PresentationCore.dll!System.Windows.Media.Visual.FireOnVisualParentChanged(System.Windows.DependencyObject oldParent = null) Line 4428 C# PresentationCore.dll!System.Windows.Media.Visual.AddVisualChild(System.Windows.Media.Visual child) Line 3165 C# PresentationFramework.dll!System.Windows.FrameworkElement.TemplateChild.set(System.Windows.UIElement value) Line 559 C# //now the two Call Stack diverge //this line contains the first difference ("Line 5227" at the end) PresentationFramework.dll!System.Windows.StyleHelper.LoadOptimizedTemplateContent(System.Windows.DependencyObject container = {System.Windows.Controls.ContentPresenter}, System.Windows.Markup.ParserContext parserContext = {System.Windows.Markup.ParserContext}, System.Windows.Markup.OptimizedTemplateContent optimizedTemplateContent, System.Windows.FrameworkTemplate frameworkTemplate = {System.Windows.DataTemplate}, System.Windows.Markup.IComponentConnector componentConnector, System.Windows.Markup.IStyleConnector styleConnector, System.Collections.Generic.List<System.Windows.DependencyObject> affectedChildren, System.Windows.UncommonField<System.Collections.Hashtable> templatedNonFeChildrenField) Line 5227 C#
    //removed deeper stack entries

    Does this make sense to anybody?

     

    Wednesday, September 7, 2011 3:09 PM

All replies

  • This seems to be a very common problem where by your event handler method gets run twice.

    It is caused by VS.NET inserting 2 wireup of the event handler:

    - once in the aspx (HTML) eg:  <asp:Button ... OnClick="btnTest_Click" />

    - and once in the VS.NET generated section (InitializeComponent) eg:
      this.btnTest.Click += new System.EventHandler(this.btnTest_Click);

    The easiest solution, imo, is to simply remove the "OnClick..." HTML markup from the .aspx page.

    Eg change this:
      <asp:Button ID="btnTest" runat="server" Text="Test" OnClick="btnTest_Click" />

    To this:
      <asp:Button ID="btnTest" runat="server" Text="Test"  />

    Rebuild, and bingo! - 1 event per click.

    Hope this helps.


    Pravin Arote, MCTS - Web Technologies
    • Proposed as answer by Pravin S Arote Thursday, September 8, 2011 10:35 AM
    • Unproposed as answer by Dunken Thursday, September 8, 2011 11:00 AM
    Thursday, September 8, 2011 10:35 AM
  • This is not the case in my app. The DataContext from my side is just set once (with my ViewModel) and this isn't done in an event handler. What's called twice is the DataContextChanged-EventHandler. I don't do anything in there except checking for the new set DC (which is null in the second call).
    Thursday, September 8, 2011 11:03 AM
  • Hi Dunken,

    What's the .NET Framework Version? From the callstack it looks like .NET3.5, just want to make sure I didn't get it wrong.

    Could you please provide a simple sample for us to reproduce this locally? It looks pretty strange if the DataContext is changed back to null by the framework. It will helps a lot if we know the scenario.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, September 9, 2011 4:03 AM
  • You got it right. It's .NET 3.5.

     

    Unfortunately, I don't have a simple sample available right now. However, please let me know if you need any additional traces, call stacks, debug excerpts...

    I already downloaded available MS code and symbols regarding this issue but couldn't figure out what causes this strange behavior...

    Friday, September 9, 2011 6:36 AM
  • Hi Dunken,

    I did some research but didn't see what could cause such problem.

    Any update on your side?


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, September 15, 2011 6:15 AM
  • Hi Min Zhu

     

    I didn't find a solution but a workaround. Let me explain a bit more into detail:

    The (global) UserControl of the twice set DataContext is used in two different assemblies. In both assemblies I used to have a IDENTICAL DataTemplates:

    <DataTemplate x:Key="UCViewModel">
        <ttt:MyUserControl DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(ctrl:ControlHostEditor.Editor).Value}"/>
    </DataTemplate>
    


    My problem as described in the post occured just in case I used the UserControl the second time:

    Example:

    -Start my app

    -Go to tab which uses UserControl (A) through DataTemplate from Assembly1 --> everything is fine; DC is set once

    -Switch to tab which uses UserControl (B) through DataTemplate from Assembly2 --> DC is set twice

    (if I do it the other way around it's exactly the opposite...)

     

    I found two workarounds:

    - instead of having my UserControl globally available I keep it separate but equal in both assemblies (bad design though)

    - make one DataTemplate look different from the other by using

    Binding RelativeSource={RelativeSource TemplatedParent} //in Assembly1<br/><br/>Binding RelativeSource={RelativeSource Self} //in Assembly2
    

     

    I know it's weird and confusing and it doesn't make any sense to me... It seems like a cache/optimization problem. However, at least it works now as expected. (I would appreciate any explanation though...)

    Thursday, September 15, 2011 7:00 AM
  • Hi Dunken,

    The binding looks a little bit unusual (RelativeSource TemplatedParent inside a DataTemplate). Could that be the reason?

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, September 20, 2011 1:57 AM