在 WPF 中拖放 TabItems?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26174695/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:35:29  来源:igfitidea点击:

Drag and Drop TabItems in WPF?

c#wpf

提问by Jason Axelrod

So I found this answered questions: Is it possible to rearrange tab items in tab control in wpf?

所以我发现了这个问题的答案: Is it possible to rerange tab items in tab control in wpf?

Using the information in that thread, I set it all up in my application:

使用该线程中的信息,我在我的应用程序中进行了全部设置:

<TabControl x:Name="tabControl">
    <TabControl.Resources>
        <Style TargetType="TabItem">
            <Setter Property="AllowDrop" Value="True"/>
            <EventSetter Event="PreviewMouseMove" Handler="TabItem_Drag"/>
            <EventSetter Event="Drop" Handler="TabItem_Drop"/>
        </Style>
    </TabControl.Resources>
</TabControl>

And the code:

和代码:

private void TabItem_Drag(object sender, MouseEventArgs e)
{
    var tabItem = e.Source as TabItem;

    if (tabItem == null)
        return;

    if (Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed)
        DragDrop.DoDragDrop(tabItem, tabItem, DragDropEffects.All);
}
private void TabItem_Drop(object sender, DragEventArgs e)
{
    var tabItemTarget = e.Source as TabItem;
    var tabItemSource = e.Data.GetData(typeof(TabItem)) as TabItem;

    if (!tabItemTarget.Equals(tabItemSource))
    {
        int sourceIndex = tabControl.Items.IndexOf(tabItemSource);
        int targetIndex = tabControl.Items.IndexOf(tabItemTarget);

        tabControl.Items.Remove(tabItemSource);
        tabControl.Items.Insert(targetIndex, tabItemSource);

        tabControl.Items.Remove(tabItemTarget);
        tabControl.Items.Insert(sourceIndex, tabItemTarget);

        tabControl.SelectedIndex = targetIndex;
    }
}

The problem is, when I drop the tab, I get the following error at

问题是,当我放下选项卡时,出现以下错误

    if (!tabItemTarget.Equals(tabItemSource))

An exception of type 'System.NullReferenceException' occurred in Scoreboard Assistant.exe but was not handled in user code

Additional information: Object reference not set to an instance of an object.

Scoreboard Assistant.exe 中出现类型为“System.NullReferenceException”的异常,但未在用户代码中处理

附加信息:未将对象引用设置为对象的实例。

When I click continue, I get the following error at

当我单击继续时,出现以下错误

        DragDrop.DoDragDrop(tabItem, tabItem, DragDropEffects.All);

An unhandled exception of type 'System.NullReferenceException' occurred in PresentationCore.dll

Additional information: Object reference not set to an instance of an object.

PresentationCore.dll 中发生类型为“System.NullReferenceException”的未处理异常

附加信息:未将对象引用设置为对象的实例。

And then the program dies. What am I doing wrong?

然后程序就死了。我究竟做错了什么?

* EDIT *

* 编辑 *

Okay, I figured out what the issue is; I just need help fixing it. If the tab item is created as follows it works perfectly fine:

好的,我想出了问题所在;我只是需要帮助修复它。如果按如下方式创建选项卡项目,则它可以正常工作:

<TabItem Header="TabItem"/>

However, my tabs are being created as follows:

但是,我的标签创建如下:

<TabItem>
    <TabItem.Header>
        <StackPanel Orientation="Horizontal">
            <Image Source="images/text.png" />
            <TextBlock Text="Text"/>
        </StackPanel>
    </TabItem.Header>
</TabItem>

As you can see, I am using a stackpanel to have an icon in the tab header. The problem seems to be that when I drag and drop the panel, instead of the e.Sourcebeing read as the tabitem, its reading the textblock within the stackpanel of the tabitem. How would I fix this?

如您所见,我使用堆栈面板在选项卡标题中有一个图标。问题似乎是,当我拖放面板时,它不是将面板e.Source读取为 tabitem,而是读取 tabitem 堆栈面板内的文本块。我将如何解决这个问题?

采纳答案by Dennis

Since the visual tree of TabItemheader can be rather complex, you can't guarantee, that drop target will be a TabIteminstance (that's what happening in your code).

由于TabItem标题的可视化树可能相当复杂,因此您无法保证放置目标将是一个TabItem实例(这就是您的代码中发生的情况)。

But you can find TabItemvia exploring visual tree:

但是你可以TabItem通过探索视觉树找到:

private TabItem GetTargetTabItem(object originalSource)
{
    var current = originalSource as DependencyObject;            

    while (current != null)
    {
        var tabItem = current as TabItem;
        if (tabItem != null)
        {
            return tabItem;
        }

        current = VisualTreeHelper.GetParent(current);
    }

    return null;
}

private void TabItem_Drop(object sender, DragEventArgs e)
{
    var tabItemTarget = GetTargetTabItem(e.OriginalSource);
    if (tabItemTarget != null)
    {
        var tabItemSource = (TabItem)e.Data.GetData(typeof(TabItem));
        if (tabItemTarget != tabItemSource)
        {
            // the rest of your code
        }
    }
}