Removing child from panel, bound to an ItemsSource
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
add a comment |
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
What objects does theRings
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 newRingControl
, 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
add a comment |
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
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
c# wpf xaml
asked Nov 20 '18 at 13:36
DeadzoneDeadzone
653723
653723
What objects does theRings
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 newRingControl
, 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
add a comment |
What objects does theRings
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 newRingControl
, 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
add a comment |
1 Answer
1
active
oldest
votes
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);
}
}
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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);
}
}
add a comment |
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);
}
}
add a comment |
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);
}
}
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);
}
}
answered Nov 20 '18 at 14:54


mm8mm8
83k81831
83k81831
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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