MVVM DockingManagerAdapter/SfChart Remove/Add error: child element is already in use

Hello,

Iam currently using the dockingcontainer and the sfchart control. I followed the MVVM approach for both controls 

I  also implemented a custom undo/redo function for my whole application with the command pattern (I know that some syncfusion controls already support that).

I created some custom views/viewmodels to plot a chart and show this chart inside the dockingcontainer as a document.
Now i would like to be able to remove one document and afterwards be able to undo that - so basically readd it.

To do that, I juste remove it from the bound collection of the dockingmanageradapter, like its done in your examples.

If i afterwards readd it to the same collection i get an error: “Specified element is already the logical child of another element. Disconnect it first” Error on second call of window. See for example: https://stackoverflow.com/questions/31340710/specified-element-is-already-the-logical-child-of-another-element-disconnect-i
I can't tell if this is more a general problem from my approach in wpf/mvvm or maybe a problem from the controls itself (that they dont get disconnected correctly)

There are of course some possible workarounds, for example i could create a new viewmodel/view instead of "reuse" the old one. But this would mean that i have to store every view specific information (like size etc, which might be changed from the user during runtime) in a model. This doesnt seem reasonable.

Can you help?

Attached is a working example. 
To reproduce: start/compile -> File -> Close -> File -> Reopen

Thanks in advance!

Attachment: workingwithwpfdockingmanagerandmvvmmaster_b30caa0b.zip

6 Replies

AI Anirudhan Iyyappan Syncfusion Team May 12, 2020 01:55 PM UTC

Hi Alexander, 
 
Thank you for contacting Syncfusion support. 
 
We can able to reproduce the reported behavior. We are currently analyzing the cause of this behavior. We will share you the further details on or before May 14th 2020. 
 
Regards, 
Anirudhan 



AI Anirudhan Iyyappan Syncfusion Team May 14, 2020 02:14 PM UTC

Hi Alexander, 
 
Thanks for your patience. 
 
Currently, we are analysing the cause for this issue. We will share you the further details by May 15th 2020. 
 
Regards, 
Anirudhan 



DD Devakumar Dhanapoosanam Syncfusion Team May 18, 2020 02:14 AM UTC

Hi Alexander, 
 
Sorry for the delay.  
 
Still we need to some more to time to analyze the cause for the reported issue and we will update the status on or before May 19, 2020. We deeply regret for this. 
 
Regards, 
Devakumar D 



DD Devakumar Dhanapoosanam Syncfusion Team May 19, 2020 10:14 AM UTC

Hi Alexander, 
 
Thanks for your patience. 
 
On further analysis, it has been resolved through sample level since you have kept that ClosedView which is already have a parent and again you have added that already have a parent view into another parent. Hence only the reported issue occurred. To resolve it, please remove the parent of closed view and add that again to the parent view as per in below, 
 
C#: [ViewModel.cs] 
 
private void OpenDocument() 
{ 
            if (ClosedView == null) 
                return; 
 
            foreach (var item in ClosedView.Series) 
            { 
                if(item.Parent != null) 
                { 
                    RemoveElementFromItsParent(item); 
                } 
            } 
 
            workspaces.Add(ClosedView); 
            ClosedView = null; 
} 
 
void RemoveElementFromItsParent(FrameworkElement el) 
{ 
            if (el.Parent == null) 
                return; 
            var panel = el.Parent as Panel; 
            if (panel != null) 
            { 
                panel.Children.Remove(el); 
                return; 
            } 
} 
 
 
Please download the sample from below link, 
 
Please let us know if you need any further assistance. 
 
Regards, 
Devakumar D 



AL Alexander May 21, 2020 11:16 AM UTC

Hello,

thank your for the support and the insight you gave for the problem. Your solution does work and solves the problem. Thanks!

However i would like to note, that there might a better solution. The genereal problem seems to be, that storing a control/view (here SfChart) in the viewmodel does not follow the mvvm pattern correctly. So it would be better to follow the approach synfusion suggest with the dockingcontainer ( see https://github.com/SyncfusionExamples/working-with-wpf-docking-manager-and-mvvm) and move that LineChartSeries into the view and make an adapter for the SfChart.

Another more hacky solution would be to extend the SfChart and use another property to bind to an interface of IChartSeries for example.


namespace 
{
    public class SfChartExtended : SfChart
    {
private Dictionary _SeriesMapping = new Dictionary();
        public IList ChartItemsSource
        {
            get { return (IList)GetValue(ChartItemsSourceProperty); }
            set { SetValue(ChartItemsSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemsSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ChartItemsSourceProperty =
            DependencyProperty.Register("ChartItemsSource", typeof(IList), typeof(SfChartExtended), new PropertyMetadata(null));

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.Property.Name == "ChartItemsSource")
            {
this.Series = new ChartSeriesCollection();
_SeriesMapping.Clear();

if (e.OldValue != null)
{
var oldcollection = e.OldValue as INotifyCollectionChanged;
oldcollection.CollectionChanged -= OnSeriesChanged;
}

if (e.NewValue != null)
{
var newcollection = e.NewValue as INotifyCollectionChanged;
newcollection.CollectionChanged += OnSeriesChanged;

foreach (var item in ((IList)e.NewValue))
{
addSeries(item as IChartSeries);
}
}
}
            base.OnPropertyChanged(e);
        }

private void addSeries(IChartSeries series)
{
// Edit this to Bind data and all charts
LineSeries newChartItem = new LineSeries() { XBindingPath = "XData", YBindingPath = "YData", ItemsSource = series.InsertSourceHere };
_SeriesMapping.Add(series,newChartItem);
this.Series.Add(newChartItem);
}
private void removeSeries(IChartSeries series)
{
ChartSeries chartItem = _SeriesMapping.Where(x => x.Key == series).Select(x => x.Value).FirstOrDefault();
_SeriesMapping.Remove(series);
this.Series.Remove(chartItem);
}

private void OnSeriesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
{
foreach (var item in e.NewItems)
{
addSeries((IChartSeries)item);
}
}
if (e.Action == NotifyCollectionChangedAction.Remove && e.OldItems != null)
{
foreach (var item in e.OldItems)
{
removeSeries((IChartSeries)item);
}
}
}
}
   
}



HM Hemalatha Marikumar Syncfusion Team May 22, 2020 04:27 AM UTC

Hi Alexander, 
 
Thanks for your update. 
 
We are glad to hear that you did with better approach. Please let us know if you need any further assistance. 
 
Regards,
Hemalatha M. 


Loader.
Up arrow icon