none
WPF 4 DataContextChanged receive a {DisconnectedItem}

    Question

  • Hi,

    I'm tring to migrate my WPF 3.5 app to WPF 4 and I have a problem with the DataContextChanged event when used in a ItemsControl. The problem is that when the ItemsControl is about to be unloaded, each item container receives a DataContextChanged with a NewValue of {DisconnectedItem}. When querying the type of this object I receive a Microsoft.Internal.NamedObject which is private. I searched in the web and the only solution I got is to check e.NewValue.GetType() == "Microsoft.Internal.NamedObject" which is very bad solution for me.

    Anybody has an idea?

    Thanks


    Frank_9
    Thursday, May 20, 2010 2:06 AM

All replies

  • Hi Frank_9,

    Could you please provide a piece of code so we can reproduce the issue? This will also help me to connect to the related team to get feedbacks.

    Regards,
    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    Sunday, May 23, 2010 12:27 PM
    Moderator
  • No problem, here's a simple set of classes that reproduce the problem.

    Thanks

    using System.Collections.ObjectModel;
    using System.Windows;
    
    namespace Framework4
    {
      public partial class MainWindow : Window
      {
        public static readonly DependencyProperty CustomSourceProperty =
          DependencyProperty.Register("CustomSource", typeof(ObservableCollection<object>), typeof(MainWindow), new UIPropertyMetadata(null));
    
        public MainWindow()
        {
          InitializeComponent();
    
          DataContext = this;
          CustomSource = new ObservableCollection<object>();
          CustomSource.Add(new ViewModel1());
        }
    
        public ObservableCollection<object> CustomSource
        {
          get { return (ObservableCollection<object>)GetValue(CustomSourceProperty); }
          set { SetValue(CustomSourceProperty, value); }
        }
    
        private void OnButtonClick(object sender, RoutedEventArgs e)
        {
          // Setting a new content unload the ListBox and View1 that is
          // used as DataTemplate for ViewModel1 will receive {DisconnectedItem}
          // as new data context
          Content = "New Content";
        }
      }
    }
    
    <Window x:Class="Framework4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Framework4"
        Title="MainWindow">
      <DockPanel>
        <Button DockPanel.Dock="Top"
            Content="Change content"
            Click="OnButtonClick" />
        <ListBox ItemsSource="{Binding Path=CustomSource}">
          <ListBox.Resources>
            <DataTemplate DataType="{x:Type local:ViewModel1}">
              <local:View1 />
            </DataTemplate>
          </ListBox.Resources>
        </ListBox>
      </DockPanel>
    </Window>
    
    
    namespace Framework4
    {
      /// <summary>
      /// An empty class that represent an arbitrary item in the ListBox.
      /// </summary>
      public class ViewModel1
      {
      }
    }
    
    using System.Windows;
    using System.Windows.Controls;
    
    namespace Framework4
    {
      /// <summary>
      /// A UserControl that represents the DataTemplate of ViewModel1 in the ListBox
      /// </summary>
      public partial class View1 : UserControl
      {
        public View1()
        {
          InitializeComponent();
    
          DataContextChanged += OnDataContextChanged;
        }
    
        private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
          // Put a break point here and after clicking the button e.NewValue contains {DisconnectedItem}
        }
      }
    }
    
    <UserControl x:Class="Framework4.View1"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
      <TextBlock Text="{Binding}" />
    </UserControl>
    
    

     

     


    Frank_9
    Wednesday, May 26, 2010 1:24 PM
  • Hi Alland, are you able to reproduce the problem on your side? I hope some news about this problem since this is the only thing that prevents us from migrating to the .NET 4.0.

     

    Thanks


    Frank_9
    Wednesday, June 02, 2010 1:24 AM
  • I am also having this problem--has there been any progress made?
    Monday, June 07, 2010 1:32 AM
  • Hi chaiguy1337, I'm waiting for feedback since for us this is a major show stopper! Do you confirm with the code I've pasted earlier that you experience the same problem?

     

    Thanks


    Frank_9
    Monday, June 07, 2010 4:35 PM
  • Frank--I created a new .NET 4 project and pasted your code in and it does indeed reproduce the problem. I've been trying to reproduce the problem how it occurs in my program but have as yet been unsuccessful. This is odd because it happens every time I run my app. I will post back if I am able to reproduce it my way.
    Monday, June 07, 2010 8:40 PM
  • I think that this occurs when we remove a ItemsControl from the visual tree. In my program, when I write Content = "New content", the ListBox that was part of the visual tree is removed from it and the view that is used as DataTemplate for my items then receive a {DisconnectedItem} in the DataContextChanged event.
    Frank_9
    Monday, June 07, 2010 10:51 PM
  • I've created another example that reproduces the problem, based on yours:

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/36aec363-9e33-45bd-81f0-1325a735cc45/?prof=required

    Basically all you need to do is change the items source an ItemsControl is bound to and the problem will occur.

    Sunday, June 13, 2010 2:42 AM
  • Any updates for this issue. For me this is a major bug!
    Frank_9
    Monday, June 28, 2010 11:04 AM
  • You can make your solution a little more robust by saving a reference to the sentinel object {DisconnectedItem} the first time you see it, then comparing against the saved value after that.

    We should have made a public way to test for {DisconnectedItem}, but it slipped through the cracks.   We'll fix that in a future release, but for now you can count on the fact that there's a unique {DisconnectedItem} object.   It's used whenever a container is removed from the visual tree, either because the corresponding item was deleted, or the collection was refreshed, or the container was scrolled off the screen and re-virtualized.

    Tuesday, June 29, 2010 12:27 AM
  • For me this is a major bug!
    Frank_9

    I second that.

    When can we expect a hotfix?

    In the meantime I'm reverting the target framework of my project back to 3.5, since we aren't using any .net4.0 specific features at the moment.

    Wednesday, July 07, 2010 11:45 AM
  • A hotfix seems required for me also. We have several places where we handle the DataContextChanged in our buisiness application. This is stopping us from migrating to .NET 4.0. The solution stated by Sam is reasonable but we have to fix our code in too much places.
    Frank_9
    Wednesday, July 07, 2010 5:17 PM
  • Please, MS - Is a hotfix available for this issue?

     

     

     

     

    Monday, September 20, 2010 7:47 PM
  • For the record, I added entry 619658 to connect bug reporting. Hope this helps to expedite ...

     

    https://connect.microsoft.com/VisualStudio/feedback/details/619658/wpf-virtualized-control-disconnecteditem-reference-when-datacontext-switch

     

    Regards, Chris

    Saturday, November 06, 2010 9:26 AM
  • Any updates on this one? Having the same problem

     

    Joachim

    Wednesday, February 02, 2011 8:45 AM
  • In my case, my DataContext is supposed to be my view model or null. Since sometimes it is DisconnectedItem instead, I just check it for "my view model or not my view model." In other works, I'm treating DisconnectedItem as null. Seems like a satisfactory workaround in my particular case.
    http://dalebarnardonwpf.wordpress.com/
    Wednesday, February 02, 2011 2:16 PM
  • Here's what I use in my code, and I am admitting upfront that it is a terrible hack, but until MSFT fixes the issue, what other choice is there?

        private bool IsItemDisconnected(object item)
        {
          bool isDisconnected = false;
    
          var itemType = item.GetType();
          if (itemType.FullName.Equals("MS.Internal.NamedObject"))
          {
            isDisconnected = true;
          }
    
          return isDisconnected;
        }
    
    I'm sure that there are more reflection properties that I could check against, but I need this to be fast, and I know the context in which I'm using it, so this is sufficient for me.

    Wednesday, February 02, 2011 6:49 PM
  • I'll second the hotfix request.

    I have an app with a tab control and navigatiogn from tab to tab blows out all my bindings;

    Some fo this is pure xaml so a simple "You can make your solution a little more robust by saving a reference to the sentinel object {DisconnectedItem} the first time you see it, then comparing against the saved value after that." is not quite as simple.

    Also some pattern samples and something in the comments of affacted controls will make it much much easier for people to find their way to realizing this is a framework cahnge from 3.5 rather than a bug. Especially as more people stat new 4.0 projects and won't see this as a conversion issue.


    http://bashamer.wordpress.com
    Thursday, December 08, 2011 12:02 AM
  • DO you suppose the issues I am having regarding layout and events post-datacontext change as described here (http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6bb1d967-98bb-4a33-aa9c-8da7b597df99) might be attributed to this glitch?

     

    Any thoughts, opinions or suggestions on this would be appreciated. Thanks.


    • Edited by XamlZealot Thursday, January 26, 2012 8:28 PM Typo
    Thursday, January 26, 2012 8:28 PM
  • I experience {DisconnectedItem}, when I use two ItemsPresenter in a ListBox control template. The first ItemsPresenter displays the items, but then gets them all disconnected. The second one works fine.

    Mikhail

    Thursday, October 17, 2013 7:25 AM
  • Not sure if there is already a solution provided for this but it's not a bug.

    It's by design. It should work this ways.

    In .NET 4.5 Microsoft change the behavior to not fire DataContextChanged event when an Item is disconnected however even when the event was still triggering all you need to do is following:

    private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
          if(e.NewValue is MyViewModel1)
          {
             //// Do whatever you wish here...
          }
        }

    Disconnecting and connecting items to data source is part of UI Virtualization.

    Containers are not being created for each data item. If 10 items are visible, 10 containers will be created and when you start scrolling up or down those containers will be disconnected from the data item source but therefore connected again to new item.

    ListBox has by default set ui virtualization to true. And as you all may have noticed the ListBox is amazingly fast and leaves nice memory footprints.

    Thursday, October 17, 2013 7:55 AM