Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Win81] Exception on Toggle in/out of view #1

Closed
EisenbergEffect opened this issue Feb 3, 2014 · 7 comments
Closed

[Win81] Exception on Toggle in/out of view #1

EisenbergEffect opened this issue Feb 3, 2014 · 7 comments
Assignees
Labels

Comments

@EisenbergEffect
Copy link
Contributor

In Win8.1, if you have a ItemsControl derived type that removes and re-adds some portion of its children and you're using the c:View.Model binding on a data template to convert child view models into their views, you hit an issue.

The issue is this. The OnModelChanged event gets fired every time that the child appears or disappears, which in and of itself would not be bad. However, the following pattern is then employed ...

  1. Use the ViewLocator to get the view.
  2. Set the ContentProperty on the target to the view.

The problem lies in that the ViewLocator attempts to use a cached view by default and that view is still part of the visual tree. Therefore, the setting the content property fails because the view is already the child of another element in the tree.

This has been tested with several Syncfusion controls that employ this visual hiding/reshowing.

The workaround is to add this override, which trades out the exception (and failure to display the view-model with instead a memory increase as the view keeps being created.

public override object GetView(object context = null) {
    return null;
}
@EisenbergEffect
Copy link
Contributor Author

From @tibel via codeplex:

a better workaround is to set CacheViews property to false in the constructor.
may attach a sample that show the issue, please.

@rufusl
Copy link

rufusl commented Apr 8, 2014

Hi,
I can reproduce this issue. It occurs for me when a view with an ItemsControl is reactivated whose ItemTemplate uses a ViewAware View.Model. I think it happens in View.cs when setting the Content property with a cached view:

var fe = view as FrameworkElement;
if (fe != null && fe.Parent != null) {
  SetContentPropertyCore(fe.Parent, null);
}

fe.Parent is null here (VisualTreeHelper.GetParent(view) also is), but when adding it to the content of a ContentControl, the exception "Element is already the child of another element." is thrown anyway. Maybe the view is still the child of an unloaded ContentPresenter and thus is not in the visual tree (so Parent is null)? I did not find a solution to this problem yet.
Here is a solution demonstrating the issue:
https://dl.dropboxusercontent.com/u/30911321/ItemsControlChildOfAnotherElement.zip
The "Switch View" button removes and reactivates the content, so that the error is thrown and the items are not rendered again.

@nigel-sampson
Copy link
Contributor

Given what you've found I'm not sure if this will be solvable, with Parent being null we have no access to the ContentPresenter previously containing the view to try and detach it.

@tibel
Copy link
Contributor

tibel commented May 11, 2014

There is actually a way to prevent the Exception without workarounds:
SomePageViewModel has to Activate() and Deactivate() all containing Items.

public class SomePageViewModel : Conductor<ItemViewModel>.Collection.AllActive
{
    public SomePageViewModel()
    {
        Items.AddRange(
        Enumerable.Range(0, 1)
            .Select(i => new ItemViewModel { DisplayName = "Item" + i }));
    }
}

The explanation is a bit longer (maybe @nigel-sampson can help here)?

@tibel
Copy link
Contributor

tibel commented May 16, 2014

The problem is not ItemViewModel using view caching, but SomePageViewModel does not handle activation/deactivation of its children. So the ItemView still is referenced by a SomePage, that is not referenced by anyone. Because of this CM has no chance to breakup the view relation and re-attach the ItemView to a new instance of SomePage.

Summary:

  • if a view model uses activation/deactivation like Screen the parent view model (conductor) has to do the same
  • from my point of view this is an user error and not a bug in CM
  • the documentation should be updated to make these dependencies more clear

@nigel-sampson
Copy link
Contributor

I'm relooking at this, I've encountered the same error in a different way, there's definitely something fishy with the xaml stack here. That being said there are ways around it.

@rufusl the solution from @tibel to activate and deactivate the view models in question would help remove this bug (as deactivate clears the views).

@nigel-sampson
Copy link
Contributor

I've added a work around to View that if a view returned from LocateForModel fails we fall back to LocateForModelType that resolves this issue.

Still working with Microsoft on why this is happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants