最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

WPF利用TabControl控件實(shí)現(xiàn)拖拽排序功能

 更新時(shí)間:2023年10月24日 13:55:15   作者:czwy  
在UI交互中,拖拽操作是一種非常簡(jiǎn)單友好的交互,這篇文章主要為大家介紹了WPF如何利用TabControl控件實(shí)現(xiàn)拖拽排序功能,需要的小伙伴可以參考一下

在UI交互中,拖拽操作是一種非常簡(jiǎn)單友好的交互。尤其是在ListBox,TabControl,ListView這類列表控件中更為常見(jiàn)。通常要實(shí)現(xiàn)拖拽排序功能的做法是自定義控件。本文將分享一種在原生控件上設(shè)置附加屬性的方式實(shí)現(xiàn)拖拽排序功能。

該方法的使用非常簡(jiǎn)單,僅需增加一個(gè)附加屬性就行。

<TabControl
    assist:SelectorDragDropAttach.IsItemsDragDropEnabled="True"
    AlternationCount="{Binding ClassInfos.Count}"
    ContentTemplate="{StaticResource contentTemplate}"
    ItemContainerStyle="{StaticResource TabItemStyle}"
    ItemsSource="{Binding ClassInfos}"
    SelectedIndex="0" />

實(shí)現(xiàn)效果如下:

主要思路

WPF中核心基類UIElement包含了DragEnter,DragLeaveDragEnter,Drop等拖拽相關(guān)的事件,因此只需對(duì)這幾個(gè)事件進(jìn)行監(jiān)聽(tīng)并做相應(yīng)的處理就可以實(shí)現(xiàn)WPF中的UI元素拖拽操作。

另外,WPF的一大特點(diǎn)是支持?jǐn)?shù)據(jù)驅(qū)動(dòng),即由數(shù)據(jù)模型來(lái)推動(dòng)UI的呈現(xiàn)。因此,可以通過(guò)通過(guò)拖拽事件處理拖拽的源位置以及目標(biāo)位置,并獲取到對(duì)應(yīng)位置渲染的數(shù)據(jù),然后操作數(shù)據(jù)集中數(shù)據(jù)的位置,從而實(shí)現(xiàn)數(shù)據(jù)和UI界面上的順序更新。

首先定義一個(gè)附加屬性類SelectorDragDropAttach,通過(guò)附加屬性IsItemsDragDropEnabled控制是否允許拖拽排序。

public static class SelectorDragDropAttach
{
    public static bool GetIsItemsDragDropEnabled(Selector scrollViewer)
    {
        return (bool)scrollViewer.GetValue(IsItemsDragDropEnabledProperty);
    }

    public static void SetIsItemsDragDropEnabled(Selector scrollViewer, bool value)
    {
        scrollViewer.SetValue(IsItemsDragDropEnabledProperty, value);
    }

    public static readonly DependencyProperty IsItemsDragDropEnabledProperty =
        DependencyProperty.RegisterAttached("IsItemsDragDropEnabled", typeof(bool), typeof(SelectorDragDropAttach), new PropertyMetadata(false, OnIsItemsDragDropEnabledChanged));

    private static readonly DependencyProperty SelectorDragDropProperty =
        DependencyProperty.RegisterAttached("SelectorDragDrop", typeof(SelectorDragDrop), typeof(SelectorDragDropAttach), new PropertyMetadata(null));

    private static void OnIsItemsDragDropEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        bool b = (bool)e.NewValue;
        Selector selector = d as Selector;
        var selectorDragDrop = selector?.GetValue(SelectorDragDropProperty) as SelectorDragDrop;
        if (selectorDragDrop != null)
            selectorDragDrop.Selector = null;
        if (b == false)
        {
            selector?.SetValue(SelectorDragDropProperty, null);
            return;
        }
        selector?.SetValue(SelectorDragDropProperty, new SelectorDragDrop(selector));

    }

}

其中SelectorDragDrop就是處理拖拽排序的對(duì)象,接下來(lái)看下幾個(gè)主要事件的處理邏輯。
通過(guò)PreviewMouseLeftButtonDown確定選中的需要拖拽操作的元素的索引

void selector_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (this.IsMouseOverScrollbar)
    {
        //Set the flag to false when cursor is over scrollbar.
        this.canInitiateDrag = false;
        return;
    }

    int index = this.IndexUnderDragCursor;
    this.canInitiateDrag = index > -1;

    if (this.canInitiateDrag)
    {
        // Remember the location and index of the SelectorItem the user clicked on for later.
        this.ptMouseDown = GetMousePosition(this.selector);
        this.indexToSelect = index;
    }
    else
    {
        this.ptMouseDown = new Point(-10000, -10000);
        this.indexToSelect = -1;
    }
}

PreviewMouseMove事件中根據(jù)需要拖拽操作的元素創(chuàng)建一個(gè)AdornerLayer,實(shí)現(xiàn)鼠標(biāo)拖著元素移動(dòng)的效果。其實(shí)拖拽移動(dòng)的只是這個(gè)AdornerLayer,真實(shí)的元素并未移動(dòng)。

void selector_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (!this.CanStartDragOperation)
        return;

    // Select the item the user clicked on.
    if (this.selector.SelectedIndex != this.indexToSelect)
        this.selector.SelectedIndex = this.indexToSelect;

    // If the item at the selected index is null, there's nothing
    // we can do, so just return;
    if (this.selector.SelectedItem == null)
        return;

    UIElement itemToDrag = this.GetSelectorItem(this.selector.SelectedIndex);
    if (itemToDrag == null)
        return;

    AdornerLayer adornerLayer = this.ShowDragAdornerResolved ? this.InitializeAdornerLayer(itemToDrag) : null;

    this.InitializeDragOperation(itemToDrag);
    this.PerformDragOperation();
    this.FinishDragOperation(itemToDrag, adornerLayer);
}

DragEnter,DragLeaveDragEnter事件中處理AdornerLayer的位置以及是否顯示。

Drop事件中確定了拖拽操作目標(biāo)位置以及渲染的數(shù)據(jù)元素,然后移動(dòng)元數(shù)據(jù),通過(guò)數(shù)據(jù)順序的變化更新界面的排序。從代碼中可以看到列表控件的ItemsSource不能為空,否則拖拽無(wú)效。這也是后邊將提到的一個(gè)缺點(diǎn)。

void selector_Drop(object sender, DragEventArgs e)
{
    if (this.ItemUnderDragCursor != null)
        this.ItemUnderDragCursor = null;

    e.Effects = DragDropEffects.None;

    var itemsSource = this.selector.ItemsSource;
    if (itemsSource == null) return;

    int itemsCount = 0;
    Type type = null;
    foreach (object obj in itemsSource)
    {
        type = obj.GetType();
        itemsCount++;
    }

    if (itemsCount < 1) return;
    if (!e.Data.GetDataPresent(type))
        return;

    object data = e.Data.GetData(type);
    if (data == null)
        return;

    int oldIndex = -1;
    int index = 0;
    foreach (object obj in itemsSource)
    {
        if (obj == data)
        {
            oldIndex = index;
            break;
        }
        index++;
    }
    int newIndex = this.IndexUnderDragCursor;

    if (newIndex < 0)
    {
        if (itemsCount == 0)
            newIndex = 0;
        else if (oldIndex < 0)
            newIndex = itemsCount;
        else
            return;
    }
    if (oldIndex == newIndex)
        return;

    if (this.ProcessDrop != null)
    {
        // Let the client code process the drop.
        ProcessDropEventArgs args = new ProcessDropEventArgs(itemsSource, data, oldIndex, newIndex, e.AllowedEffects);
        this.ProcessDrop(this, args);
        e.Effects = args.Effects;
    }
    else
    {
        dynamic dItemsSource = itemsSource;
        if (oldIndex > -1)
            dItemsSource.Move(oldIndex, newIndex);
        else
            dItemsSource.Insert(newIndex, data);
        e.Effects = DragDropEffects.Move;
    }
}

優(yōu)點(diǎn)與缺點(diǎn)

優(yōu)點(diǎn):

  • 用法簡(jiǎn)單,封裝好拖拽操作的附加屬性后,只需一行代碼實(shí)現(xiàn)拖拽功能。
  • 對(duì)現(xiàn)有項(xiàng)目友好,對(duì)于已有項(xiàng)目需要擴(kuò)展拖拽操作排序功能,無(wú)需替換控件。
  • 支持多種列表控件擴(kuò)展。派生自SelectorListBox,TabControlListView,ComboBox都可使用該方法。

缺點(diǎn):

  • 僅支持通過(guò)數(shù)據(jù)綁定動(dòng)態(tài)渲染的列表控件,XAML硬編碼或者后臺(tái)代碼循環(huán)添加列表元素創(chuàng)建的列表控件不適用該方法。
  • 僅支持列表控件內(nèi)的元素拖拽,不支持穿梭框拖拽效果。
  • 不支持同時(shí)拖拽多個(gè)元素。

小結(jié)

本文介紹列表拖拽操作的解決方案不算完美,功能簡(jiǎn)單但輕量,并且很好的體現(xiàn)了WPF的數(shù)據(jù)驅(qū)動(dòng)的思想。個(gè)人非常喜歡這種方式,它能讓我們輕松的實(shí)現(xiàn)列表數(shù)據(jù)的增刪以及排序操作,而不是耗費(fèi)時(shí)間和精力去自定義可增刪數(shù)據(jù)的控件。

到此這篇關(guān)于WPF利用TabControl控件實(shí)現(xiàn)拖拽排序功能的文章就介紹到這了,更多相關(guān)WPF TabControl拖拽排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

岐山县| 齐河县| 舞阳县| 海淀区| 旬邑县| 香河县| 密山市| 沂源县| 周至县| 保亭| 洞头县| 崇左市| 日照市| 祁东县| 罗甸县| 古蔺县| 依兰县| 迁安市| 藁城市| 平阳县| 福贡县| 钟山县| 安泽县| 丽江市| 明溪县| 玉屏| 黑山县| 江津市| 玉田县| 会同县| 宽城| 韶关市| 阜宁县| 紫云| 高台县| 泉州市| 阿荣旗| 汝南县| 晋城| 胶州市| 射洪县|