WPF 筆記 | Adorner ListView舉例

2024/02/19閱讀時間約 16 分鐘

成果

成果展示

成果展示

應用需求

使用者在操作時提示給使用者會插入的位置。


實作

1.建立控制元件ListView

使用使用到拖曳需要將Drop的功能開啟。

<ListView 
AllowDrop="True"
MouseMove="ListView_MouseMove"
DragDrop.Drop="ListView_Drop"
DragDrop.DragOver="ListView_DragOver">
<ListViewItem Content="Item1" Padding="0 10"/>
<ListViewItem Content="Item2" Padding="0 10"/>
<ListViewItem Content="Item3" Padding="0 10"/>
<ListViewItem Content="Item4" Padding="0 10"/>
</ListView>

2.實作 DragListViewItemAdorner

重新覆寫(override)繪製方法,在需要插入的位置的地方繪製一條線提示使用者。

/// <summary>
/// 拖曳ListViewItem時產生的繪圖
/// </summary>
public class DragListViewItemAdorner : Adorner
{
/// <summary>
/// 插入此元件的上面或下面位置
/// </summary>
public AlignmentY DragAlign = AlignmentY.Bottom;

public DragListViewItemAdorner(UIElement adornedElement) : base(adornedElement) { }
public DragListViewItemAdorner(UIElement adornedElement, AlignmentY align) : base(adornedElement)
{
DragAlign = align;
}
protected override void OnRender(DrawingContext drawingContext)
{
Rect adornedElementRect = new Rect(this.AdornedElement.RenderSize);
Pen renderPen = new Pen(new SolidColorBrush(Colors.Navy), 1.5);
if (DragAlign == AlignmentY.Bottom)
drawingContext.DrawLine(renderPen, adornedElementRect.BottomLeft, adornedElementRect.BottomRight);
else if (DragAlign == AlignmentY.Top)
drawingContext.DrawLine(renderPen, adornedElementRect.TopLeft, adornedElementRect.TopRight);
}
}

3.拖曳定義

設定拖曳的是ListViewItem時才會有效果。

private void ListView_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (sender is ListView LVControl && LVControl.SelectedItem != null)
{
DragDrop.DoDragDrop(LVControl, LVControl.SelectedItem, DragDropEffects.Move);
}
}
}

4.拖曳時的事件

鼠標移動時偵測是否停留在ListViewItem上若不是則會改變鼠標圖示,若停留在ListViewItem上則會判斷該插入的是此ListViewItem的上面或下面位置。

private void ListView_DragOver(object sender, DragEventArgs e)
{ Point currentPosition;
AlignmentY alignY;
e.Effects = DragDropEffects.None;

if (e.Data.GetData(typeof(ListViewItem)) is ListViewItem el)
{
if ( e.Source is ListViewItem selectItem)
{
currentPosition = e.GetPosition(selectItem);
alignY = currentPosition.Y > (selectItem.ActualHeight / 2) ? AlignmentY.Bottom : AlignmentY.Top;
e.Effects = DragDropEffects.Move;
SetElementAdorner(selectItem, alignY);
}
else
{
RemoveElementAdorner();
}
}
}

5.拖曳完成事件

檢查選取的Item與插入的item是否不同,則會判斷該插入的位置進行插入。

private void ListView_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetData(typeof(ListViewItem)) is ListViewItem el)
{
if( e.Source is ListViewItem selectItem)
{
ListView lvControl = (ListView)sender;
if (selectItem != el)
{
// 改變控建順序
AlignmentY alignY;
int i1, i2, diff;
i1 = lvControl.Items.IndexOf(el);
i2 = lvControl.Items.IndexOf(selectItem);
alignY = GetElementAdornerAlignmentY(el);
if(alignY != AlignmentY.Center)
{
diff = i2 > i1 ? 1 : -1;
if (i1 >= 0 && i2 >= 0)
{
ListViewItem item1;
item1 = (ListViewItem)lvControl.Items[i1];
lvControl.Items.RemoveAt(i1);
if (i2 > i1)
{
if (alignY == AlignmentY.Top)
lvControl.Items.Insert(i2 - 1, item1);
else if (alignY == AlignmentY.Bottom)
lvControl.Items.Insert(i2, item1);
}
else
{
if (alignY == AlignmentY.Top)
lvControl.Items.Insert(i2, item1);
else if (alignY == AlignmentY.Bottom)
lvControl.Items.Insert(i2 + 1, item1);
}
}
}
}
}
RemoveElementAdorner();
}
}

6.Adorner 相關方法

取得目前該插入的位置,設置方法和移除方法。

private UIElement AdornerElement;

/// <summary>
/// 取得 Adorner的插入位置
/// </summary>
private AlignmentY GetElementAdornerAlignmentY(UIElement el)
{
AdornerLayer elAdornerLayer = AdornerLayer.GetAdornerLayer(el);
Adorner[] AdronerLayers = elAdornerLayer.GetAdorners(AdornerElement);
if (AdronerLayers != null)
{
if (AdronerLayers.Length > 0)
if (AdronerLayers[0] is DragListViewItemAdorner adornerly)
return adornerly.DragAlign;
}
return AlignmentY.Center;
}
/// <summary>
/// 設置 Adorner
/// </summary>
private void SetElementAdorner(UIElement el, AlignmentY align)
{
AdornerLayer elAdornerLayer;
if (el == AdornerElement && AdornerElement != null)
{
elAdornerLayer = AdornerLayer.GetAdornerLayer(AdornerElement);
Adorner[] AdronerLayers = elAdornerLayer.GetAdorners(AdornerElement);
if (AdronerLayers != null)
{
AlignmentY aligny = GetElementAdornerAlignmentY(AdornerElement);

if (AdronerLayers.Length > 0)
{
if (AdronerLayers[0] is DragListViewItemAdorner adornerly)
{
if (adornerly.DragAlign != align)
{
adornerly.DragAlign = align;
adornerly.InvalidateVisual();
}
}
}
}
}
else
{
if (AdornerElement != null)
RemoveElementAdorner();
AdornerElement = el;

elAdornerLayer = AdornerLayer.GetAdornerLayer(AdornerElement);
if (elAdornerLayer != null)
elAdornerLayer.Add(new DragListViewItemAdorner(AdornerElement, align));
}
}
/// <summary>
/// 移除 Adorner
/// </summary>
private void RemoveElementAdorner()
{
if( AdornerElement != null)
{
AdornerLayer elAdornerLayer = AdornerLayer.GetAdornerLayer(AdornerElement);
Adorner[] AdronerLayers = elAdornerLayer.GetAdorners(AdornerElement);
if (AdronerLayers != null)
{
for (int i = 0; i < AdronerLayers.Length; i++)
elAdornerLayer.Remove(AdronerLayers[i]);
}
AdornerElement = null;
}
}




0會員
2內容數
留言0
查看全部
發表第一個留言支持創作者!
從 Google News 追蹤更多 vocus 的最新精選內容