Removing child from panel, bound to an ItemsSource












0















I'm trying to create a drag and drop functionality for a couple of buttons which are contained in an ObservableCollection<> in the view model, the collection is later used as an ItemsSource for a StackPanel:



This is the xaml structure:



<ItemsControl x:Name="RingHolder" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding Rings}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<customControls:RingsStackpanel Orientation="Vertical" VerticalAlignment="Bottom"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<customControls:RingControl VerticalAlignment="Stretch" Height="50"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>


Where RingsStackPanel inherits from StackPanel and RingControl inherits from Button.



In order to allow the button to be dragged around freely I want to detach it from it's parent like so:



if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
{
if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel)
{
ringStackPanel.Children.Remove(contentPresenter);
}
}


However I get the following exception:




InvalidOperationException:



Cannot explicitly modify Children collection of Panel used as ItemsPanel for ItemsControl. ItemsControl generates child elements for Panel




Which makes sense, I can only modify it by modifying the ItemsSource that is bound to it, however in this scenario, removing an item from the ObservableCollection<> causes the selected Button to disappear as it's being destroyed. Is there anyway I can allow my Button to move around freely, without creating a clone of it (this would be nigh impossible as the project currently is).










share|improve this question























  • What objects does the Rings collection contain? What should happen when you drop your button somewhere?

    – dymanoid
    Nov 20 '18 at 13:49











  • @dymanoid I don't believe that this information is relevant for the sake of this question, the collection contains ViewModels, from which I am unable to generate a new RingControl, so it has to be the one already created and visible, when I drop the button I will assign it to a different collection.

    – Deadzone
    Nov 20 '18 at 13:54
















0















I'm trying to create a drag and drop functionality for a couple of buttons which are contained in an ObservableCollection<> in the view model, the collection is later used as an ItemsSource for a StackPanel:



This is the xaml structure:



<ItemsControl x:Name="RingHolder" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding Rings}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<customControls:RingsStackpanel Orientation="Vertical" VerticalAlignment="Bottom"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<customControls:RingControl VerticalAlignment="Stretch" Height="50"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>


Where RingsStackPanel inherits from StackPanel and RingControl inherits from Button.



In order to allow the button to be dragged around freely I want to detach it from it's parent like so:



if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
{
if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel)
{
ringStackPanel.Children.Remove(contentPresenter);
}
}


However I get the following exception:




InvalidOperationException:



Cannot explicitly modify Children collection of Panel used as ItemsPanel for ItemsControl. ItemsControl generates child elements for Panel




Which makes sense, I can only modify it by modifying the ItemsSource that is bound to it, however in this scenario, removing an item from the ObservableCollection<> causes the selected Button to disappear as it's being destroyed. Is there anyway I can allow my Button to move around freely, without creating a clone of it (this would be nigh impossible as the project currently is).










share|improve this question























  • What objects does the Rings collection contain? What should happen when you drop your button somewhere?

    – dymanoid
    Nov 20 '18 at 13:49











  • @dymanoid I don't believe that this information is relevant for the sake of this question, the collection contains ViewModels, from which I am unable to generate a new RingControl, so it has to be the one already created and visible, when I drop the button I will assign it to a different collection.

    – Deadzone
    Nov 20 '18 at 13:54














0












0








0








I'm trying to create a drag and drop functionality for a couple of buttons which are contained in an ObservableCollection<> in the view model, the collection is later used as an ItemsSource for a StackPanel:



This is the xaml structure:



<ItemsControl x:Name="RingHolder" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding Rings}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<customControls:RingsStackpanel Orientation="Vertical" VerticalAlignment="Bottom"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<customControls:RingControl VerticalAlignment="Stretch" Height="50"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>


Where RingsStackPanel inherits from StackPanel and RingControl inherits from Button.



In order to allow the button to be dragged around freely I want to detach it from it's parent like so:



if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
{
if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel)
{
ringStackPanel.Children.Remove(contentPresenter);
}
}


However I get the following exception:




InvalidOperationException:



Cannot explicitly modify Children collection of Panel used as ItemsPanel for ItemsControl. ItemsControl generates child elements for Panel




Which makes sense, I can only modify it by modifying the ItemsSource that is bound to it, however in this scenario, removing an item from the ObservableCollection<> causes the selected Button to disappear as it's being destroyed. Is there anyway I can allow my Button to move around freely, without creating a clone of it (this would be nigh impossible as the project currently is).










share|improve this question














I'm trying to create a drag and drop functionality for a couple of buttons which are contained in an ObservableCollection<> in the view model, the collection is later used as an ItemsSource for a StackPanel:



This is the xaml structure:



<ItemsControl x:Name="RingHolder" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding Rings}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<customControls:RingsStackpanel Orientation="Vertical" VerticalAlignment="Bottom"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<customControls:RingControl VerticalAlignment="Stretch" Height="50"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>


Where RingsStackPanel inherits from StackPanel and RingControl inherits from Button.



In order to allow the button to be dragged around freely I want to detach it from it's parent like so:



if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
{
if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel)
{
ringStackPanel.Children.Remove(contentPresenter);
}
}


However I get the following exception:




InvalidOperationException:



Cannot explicitly modify Children collection of Panel used as ItemsPanel for ItemsControl. ItemsControl generates child elements for Panel




Which makes sense, I can only modify it by modifying the ItemsSource that is bound to it, however in this scenario, removing an item from the ObservableCollection<> causes the selected Button to disappear as it's being destroyed. Is there anyway I can allow my Button to move around freely, without creating a clone of it (this would be nigh impossible as the project currently is).







c# wpf xaml






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 20 '18 at 13:36









DeadzoneDeadzone

653723




653723













  • What objects does the Rings collection contain? What should happen when you drop your button somewhere?

    – dymanoid
    Nov 20 '18 at 13:49











  • @dymanoid I don't believe that this information is relevant for the sake of this question, the collection contains ViewModels, from which I am unable to generate a new RingControl, so it has to be the one already created and visible, when I drop the button I will assign it to a different collection.

    – Deadzone
    Nov 20 '18 at 13:54



















  • What objects does the Rings collection contain? What should happen when you drop your button somewhere?

    – dymanoid
    Nov 20 '18 at 13:49











  • @dymanoid I don't believe that this information is relevant for the sake of this question, the collection contains ViewModels, from which I am unable to generate a new RingControl, so it has to be the one already created and visible, when I drop the button I will assign it to a different collection.

    – Deadzone
    Nov 20 '18 at 13:54

















What objects does the Rings collection contain? What should happen when you drop your button somewhere?

– dymanoid
Nov 20 '18 at 13:49





What objects does the Rings collection contain? What should happen when you drop your button somewhere?

– dymanoid
Nov 20 '18 at 13:49













@dymanoid I don't believe that this information is relevant for the sake of this question, the collection contains ViewModels, from which I am unable to generate a new RingControl, so it has to be the one already created and visible, when I drop the button I will assign it to a different collection.

– Deadzone
Nov 20 '18 at 13:54





@dymanoid I don't believe that this information is relevant for the sake of this question, the collection contains ViewModels, from which I am unable to generate a new RingControl, so it has to be the one already created and visible, when I drop the button I will assign it to a different collection.

– Deadzone
Nov 20 '18 at 13:54












1 Answer
1






active

oldest

votes


















1














You could remove the data item from the source collection and add a public method to your RingsStackpanel class that removes the visual from the logical tree:



public class RingsStackpanel : StackPanel
{
...
public void RemoveElement(Visual visual) => RemoveVisualChild(visual);
}


You should then be able to handle the Unloaded event of the ContentPresenter and remove its parent-child with the StackPanel. Something like this:



if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
{
if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel
&& RingHolder.ItemsSource is ObservableCollection<YourItemType> dataItems
&& contentPresenter.DataContext is YourItemType dataItem)
{
//wait for the ContentPresenter to get unloaded
RoutedEventHandler handler = null;
handler = (ss, ee) =>
{
//remove the parent-child relationship:
ringStackPanel.RemoveElement(contentPresenter);

contentPresenter.Unloaded -= handler;
};
//remove the data object
dataItems.Remove(dataItem);
}
}





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53394245%2fremoving-child-from-panel-bound-to-an-itemssource%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    You could remove the data item from the source collection and add a public method to your RingsStackpanel class that removes the visual from the logical tree:



    public class RingsStackpanel : StackPanel
    {
    ...
    public void RemoveElement(Visual visual) => RemoveVisualChild(visual);
    }


    You should then be able to handle the Unloaded event of the ContentPresenter and remove its parent-child with the StackPanel. Something like this:



    if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
    {
    if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel
    && RingHolder.ItemsSource is ObservableCollection<YourItemType> dataItems
    && contentPresenter.DataContext is YourItemType dataItem)
    {
    //wait for the ContentPresenter to get unloaded
    RoutedEventHandler handler = null;
    handler = (ss, ee) =>
    {
    //remove the parent-child relationship:
    ringStackPanel.RemoveElement(contentPresenter);

    contentPresenter.Unloaded -= handler;
    };
    //remove the data object
    dataItems.Remove(dataItem);
    }
    }





    share|improve this answer




























      1














      You could remove the data item from the source collection and add a public method to your RingsStackpanel class that removes the visual from the logical tree:



      public class RingsStackpanel : StackPanel
      {
      ...
      public void RemoveElement(Visual visual) => RemoveVisualChild(visual);
      }


      You should then be able to handle the Unloaded event of the ContentPresenter and remove its parent-child with the StackPanel. Something like this:



      if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
      {
      if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel
      && RingHolder.ItemsSource is ObservableCollection<YourItemType> dataItems
      && contentPresenter.DataContext is YourItemType dataItem)
      {
      //wait for the ContentPresenter to get unloaded
      RoutedEventHandler handler = null;
      handler = (ss, ee) =>
      {
      //remove the parent-child relationship:
      ringStackPanel.RemoveElement(contentPresenter);

      contentPresenter.Unloaded -= handler;
      };
      //remove the data object
      dataItems.Remove(dataItem);
      }
      }





      share|improve this answer


























        1












        1








        1







        You could remove the data item from the source collection and add a public method to your RingsStackpanel class that removes the visual from the logical tree:



        public class RingsStackpanel : StackPanel
        {
        ...
        public void RemoveElement(Visual visual) => RemoveVisualChild(visual);
        }


        You should then be able to handle the Unloaded event of the ContentPresenter and remove its parent-child with the StackPanel. Something like this:



        if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
        {
        if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel
        && RingHolder.ItemsSource is ObservableCollection<YourItemType> dataItems
        && contentPresenter.DataContext is YourItemType dataItem)
        {
        //wait for the ContentPresenter to get unloaded
        RoutedEventHandler handler = null;
        handler = (ss, ee) =>
        {
        //remove the parent-child relationship:
        ringStackPanel.RemoveElement(contentPresenter);

        contentPresenter.Unloaded -= handler;
        };
        //remove the data object
        dataItems.Remove(dataItem);
        }
        }





        share|improve this answer













        You could remove the data item from the source collection and add a public method to your RingsStackpanel class that removes the visual from the logical tree:



        public class RingsStackpanel : StackPanel
        {
        ...
        public void RemoveElement(Visual visual) => RemoveVisualChild(visual);
        }


        You should then be able to handle the Unloaded event of the ContentPresenter and remove its parent-child with the StackPanel. Something like this:



        if (VisualTreeHelper.GetParent(this) is ContentPresenter contentPresenter)
        {
        if (VisualTreeHelper.GetParent(contentPresenter) is RingsStackpanel ringStackPanel
        && RingHolder.ItemsSource is ObservableCollection<YourItemType> dataItems
        && contentPresenter.DataContext is YourItemType dataItem)
        {
        //wait for the ContentPresenter to get unloaded
        RoutedEventHandler handler = null;
        handler = (ss, ee) =>
        {
        //remove the parent-child relationship:
        ringStackPanel.RemoveElement(contentPresenter);

        contentPresenter.Unloaded -= handler;
        };
        //remove the data object
        dataItems.Remove(dataItem);
        }
        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 20 '18 at 14:54









        mm8mm8

        83k81831




        83k81831






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53394245%2fremoving-child-from-panel-bound-to-an-itemssource%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            MongoDB - Not Authorized To Execute Command

            How to fix TextFormField cause rebuild widget in Flutter

            in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith