C# 正在从面板中删除绑定到ItemsSource的子项

C# 正在从面板中删除绑定到ItemsSource的子项,c#,wpf,xaml,C#,Wpf,Xaml,我正在尝试为视图模型中的可观察集合中包含的两个按钮创建拖放功能,该集合稍后用作堆栈面板的项资源: 这是xaml结构: <ItemsControl x:Name="RingHolder" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding Rings}"> <ItemsControl.ItemsPanel>

我正在尝试为视图模型中的
可观察集合
中包含的两个按钮创建拖放功能,该集合稍后用作
堆栈面板的
项资源

这是xaml结构:

<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>
但是,我得到以下例外情况:

无效操作例外:

无法显式修改用作ItemsControl的ItemsPanel的面板的子集合。ItemsControl为面板生成子元素


这是有道理的,我只能通过修改绑定到它的
ItemsSource
来修改它,但是在这种情况下,从
observedcollection
中删除一个项目会导致选中的
按钮在被销毁时消失。我是否可以允许我的
按钮
自由移动,而无需创建它的克隆(这与项目目前的情况几乎不可能)。

您可以从源集合中删除数据项,并向您的
RingsStackpanel
类添加一个公共方法,从逻辑树中删除视觉:

public class RingsStackpanel : StackPanel
{
    ...
    public void RemoveElement(Visual visual) => RemoveVisualChild(visual);
}
然后,您应该能够处理
ContentPresenter
unload
事件,并使用
StackPanel
删除其父-子事件。大概是这样的:

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);
    }
}
if(VisualTreeHelper.GetParent(此)是ContentPresenter ContentPresenter)
{
如果(VisualTreeHelper.GetParent(contentPresenter)为RingsStackpanel ringStackPanel
&&RingHolder.ItemsSource是可观察的收集数据项
&&contentPresenter.DataContext是您的项目类型(dataItem)
{
//等待ContentPresenter卸载
RoutedEventHandler处理程序=null;
处理程序=(ss,ee)=>
{
//删除父子关系:
ringStackPanel.RemoveElement(contentPresenter);
contentPresenter.unload-=处理程序;
};
//删除数据对象
dataItems.Remove(dataItem);
}
}

环集合包含哪些对象?当您将按钮放在某个地方时会发生什么情况?@dymanoid我不认为这些信息与此问题相关,因为集合包含ViewModels,我无法从中生成新的
RingControl
,因此它必须是已创建且可见的,当我放下按钮时,我会将它分配给不同的集合。
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);
    }
}