[WPF] ListBox에서 우클릭시 커서위치의 ListBoxItem에 ContextMenu 열기

윈폼에서는 IndexFromPoint 메서드를 통해 클릭이벤트가 발생된 커서 위치의 ListBoxItem의 Index를 쉽게 가져올 수 있었지만 wpf에서는 직접 알아내야 한다.

 

일단 Context Munu를 만들어야한다.

 

ContextMenu contextMenu = new ContextMenu();

MenuItem menuItemRename = new MenuItem();
menuItemRename.Header = "이름 바꾸기";
contextMenu.Items.Add(menuItemRename);
MenuItem menuItemDelete = new MenuItem();
menuItemDelete.Header = "삭제";
contextMenu.Items.Add(menuItemDelete);

 

wpf의 ListBox는 MouseDown이벤트가 작동이 안되므로 PreviewMouseRightButtonDown이벤트나 MouseRightButtonUp이벤트를 사용해야한다.

 

방법1. ListBox의 아이템들을 for문으로 돌려서 현재 마우스위치와 일치하는 아이템의 index를 찾아낸다.

private void listBox_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{

    int index = -1;
    for (int i = 0; i < listBox.Items.Count; i++)
    {
        ListBoxItem listBoxItem = listBox.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
        if (listBoxItem == null) continue;
        Rect bounds = VisualTreeHelper.GetDescendantBounds(listBoxItem);
        if (bounds.Contains(e.GetPosition(listBoxItem)))
        {
            index = i;
            break;
        }
    }
    if (index == -1) { return; }

 

    //여기에 필요한 작업을 한다.

    listBox.SelectedItem = listBox.Items.GetItemAt(index); //해당 index의 아이템을 선택한다.

    contextMenu.IsOpen = true; //contextMenu를 보인다.

}

 

반응형

 

 

 

방법2. InputHitTest메서드를 이용해 우클릭된 위치의 ListBoxItem의 정보를 FrameworkElement로 가져와 다시 ListBoxItem으로 변환한다.

private void listBox_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{

    FrameworkElement element = listBox.InputHitTest(e.GetPosition(listBox)) as FrameworkElement;

    if (element.DataContext == null) { return; }

    ListBoxItem listBoxItem = listBox.ItemContainerGenerator.ContainerFromItem(element.DataContext) as ListBoxItem;

 

    //여기에 필요한 작업을 한다.

    int index = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem); //index가 알고싶다면 이렇게
    listBoxItem.IsSelected = true; //index를 알 필요없이 간편하게 아이템을 선택할 수 있다.

    contextMenu.IsOpen = true; //contextMenu를 보인다.

}

 

wpf에서는 contextMenu.IsOpen = true; 로 마우스커서좌표를 확인할 필요없이 현재 마우스 좌표에 contextMenu가 나타났다.

그 점은 윈폼보다 편리하다.