Как (полностью) реализовать редактирование на месте в ListBox? - PullRequest
3 голосов
/ 03 августа 2011

Я создаю приложение, в котором ListBox отображает свойства Description своих элементов. Я хочу реализовать те же функции редактирования на месте, которые вы найдете, скажем, при редактировании имен файлов в проводнике Windows, и я считаю, что это большая работа.

На данный момент у меня есть ContextMenu, который инициирует редактирование. Он связан с командой в модели представления, которая устанавливает свойство IsEditingDescription. Шаблон элемента стилизован таким образом, что он отображает Description в TextBlock, когда IsEditingDescription - false, и в TextBox, когда IsEditingDescription - true. Сеттер на Description устанавливает IsEditingDescription в значение false после установки описания.

Это работает замечательно хорошо. Но есть некоторые вещи, которые он не делает, что он должен:

  • Пользователь должен иметь возможность начать редактирование, нажав F2.
  • Пользователь должен иметь возможность отменить редактирование, нажав ESC.
  • Пользователь должен иметь возможность подтвердить редактирование, нажав ENTER.
  • Когда пользователь нажимает второй раз на выбранный элемент, он должен начать редактирование.
  • Текст описания следует выбирать при появлении текстового поля

Я думаю, что могу справиться с первыми тремя пунктами с помощью команд и привязок клавиш, хотя я пока не очень понимаю, как делать привязки клавиш. Но я не могу придумать MVVMish способ сделать два других. Есть один?

Ответы [ 2 ]

2 голосов
/ 03 августа 2011

это было то, что мне приходилось делать снова и снова, поэтому я решил расширить элемент управления ListView и добавил события ItemKeyDown, ItemKeyUp и ItemDoubleClick, которые запускаются там, где происходят эти события, когда элемент в ListView находится в фокусе. ListView является производным от ListBox, поэтому вы сможете довольно легко его перенести.

/ Fx / ListView.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;

namespace Fx
{
    public static class Func
    {
        /// <summary>
        /// Finds a specific type of parent up the visual tree.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dep"></param>
        /// <returns></returns>
        public static T FindParent<T>(this object obj)
        {
            DependencyObject dep = obj as DependencyObject;
            while ((dep != null) && !(dep is T))
            {
                dep = VisualTreeHelper.GetParent(dep);
            }
            return (dep != null) ? (T)Convert.ChangeType(dep, typeof(T)) : default(T);
        }
    }

    public class ListView:System.Windows.Controls.ListView
    {

        #region public event KeyboardEventHandler ItemKeyDown;
        /// <summary>
        /// Occurs when a key is pressed when a ListViewItem in this
        /// ListView is in focus.
        /// </summary>
        public event KeyEventHandler ItemKeyDown;

        /// <summary>
        /// Raises the ItemKeyDown event for a ListViewitem in this ListView.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="e"></param>
        public void OnItemKeyDown(ListViewItem item, KeyEventArgs e)
        {
            if (ItemKeyDown != null)
                ItemKeyDown(item, e);
        }

        /// <summary>
        /// Handle they KeyDown event on the ListView, find the related
        /// ListViewItem and raise the ItemKeyDown event respectively.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListView_KeyDown(object sender, KeyEventArgs e)
        {
            ListViewItem item = Func.FindParent<ListViewItem>(e.OriginalSource);
            if (item != null)
                OnItemKeyDown(item, e);
        }
        #endregion

        #region public event KeyboardEventHandler ItemKeyUp;
        /// <summary>
        /// Occurs when a key is released when a ListViewItem in this
        /// ListView is in focus.
        /// </summary>
        public event KeyEventHandler ItemKeyUp;

        /// <summary>
        /// Raises the ItemKeyUp event for a ListViewitem in this ListView.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="e"></param>
        public void OnItemKeyUp(ListViewItem item, KeyEventArgs e)
        {
            if (ItemKeyUp != null)
                ItemKeyUp(item, e);
        }

        /// <summary>
        /// Handle they KeyUp event on the ListView, find the related
        /// ListViewItem and raise the ItemKeyUp event respectively.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListView_KeyUp(object sender, KeyEventArgs e)
        {
            ListViewItem item = Func.FindParent<ListViewItem>(e.OriginalSource);
            if (item != null)
                OnItemKeyUp(item, e);
        }
        #endregion

        #region public event MouseButtonEventHandler ItemDoubleClick;
        /// <summary>
        /// Occurs when a ListViewItem in this Listview is double clicked.
        /// </summary>
        public event MouseButtonEventHandler ItemDoubleClick;

        /// <summary>
        /// Raise the ItemDoubleClick event for a ListViewItem.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="e"></param>
        public void OnItemDoubleClick(ListViewItem item, MouseButtonEventArgs e)
        {
            if (ItemDoubleClick != null)
                ItemDoubleClick(item, e);
        }

        /// <summary>
        /// Handle the MouseDoubleClick event for the ListView, find the related
        /// ListViewItem and raise the ItemDoubleClick event respectively.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ListViewItem item = Func.FindParent<ListViewItem>(e.OriginalSource);
            if (item != null)
                OnItemDoubleClick(item, e);
        }
        #endregion

        public ListView()
        {
            MouseDoubleClick += new MouseButtonEventHandler(ListView_MouseDoubleClick);
            KeyDown += new KeyEventHandler(ListView_KeyDown);
            KeyUp += new KeyEventHandler(ListView_KeyUp);
        }
    }
}

Теперь, чтобы использовать это ... / Страницы / EmployeesPage.xaml

<UserControl x:Class="TestApp.Pages.EmployeesPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:fx="clr-namespace:Fx"
             Width="800" Height="450">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0">
            <TextBlock Text="List Items" FontWeight="Bold" FontSize="18" />

            <!-- here is the main part -->
            <fx:ListView x:Name="EmployeesList" ItemDoubleClick="EmployeesList_ItemDoubleClick" ItemKeyDown="EmployeesList_ItemKeyDown" />
            <!-- main part ends here -->

        </StackPanel>
    </Grid>
</UserControl>

/ Страницы / EmployeesPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TestApp.Pages
{
    /// <summary>
    /// Interaction logic for EmployeesPage.xaml
    /// </summary>
    public partial class EmployeesPage : UserControl
    {
        public EmployeesPage()
        {
            InitializeComponent();

            // Fill the ListView with data...
            // EmployeesList.ItemsSource = SomeObservableCollectionOrDataSource
        }

        private void EmployeesList_ItemDoubleClick(object sender, MouseButtonEventArgs e)
        {
            MessageBox.Show("an item was double clicked");

            ListViewItem item = sender as ListViewItem;
            // entityType obj = item.DataContext as entityType

            // you can begin editing here
        }

        private void EmployeesList_ItemKeyDown(object sender, KeyEventArgs e)
        {
            MessageBox.Show(e.Key.ToString() + " key was pressed on an item");

            ListViewItem item = sender as ListViewItem;
            // entityType obj = item.DataContext as entityType

            if (e.Key == Key.F2)
            {
                // begin editing here
            }
            else if (e.Key == Key.Enter)
            {
                // end editing here
            }
            else if (e.Key == Key.Escape)
            {
                // cancel editing here
            }
        }
    }
}

Надеюсь, это хоть как-то пригодится тебе ... Удачи.

0 голосов
/ 03 августа 2011

Что касается обеспечения выбора текста при входе в режим редактирования, я ранее использовал следующее поведение, прикрепленное к текстовым полям в другом моем проекте.Это в VB, но должно быть довольно простым.

Public Class SelectAllOnFocusTextboxBehavior
    Inherits Behavior(Of TextBox)

    Protected Overrides Sub OnAttached()
        MyBase.OnAttached()
        AddHandler AssociatedObject.GotKeyboardFocus, AddressOf AssociatedObjectGotKeyboardFocus

    End Sub
    Protected Overrides Sub OnDetaching()
        MyBase.OnDetaching()
        RemoveHandler AssociatedObject.GotKeyboardFocus, AddressOf AssociatedObjectGotKeyboardFocus

    End Sub

    Private Sub AssociatedObjectGotKeyboardFocus(ByVal sender As Object, ByVal e As KeyboardFocusChangedEventArgs)
        AssociatedObject.SelectAll()
    End Sub

End Class
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...