Перетаскивание ListBox не оставляет объект все время - PullRequest
0 голосов
/ 25 февраля 2020

У нас есть список, который мы используем для отображения столбцов в сетке. Пользователь может проверить столбцы, которые он хочет отобразить, и перетащить столбец, чтобы изменить порядок столбцов, отображаемых в сетке. Мы реализуем перетаскивание с пользовательским визуалом и использовали эту статью и эту статью для справки. Вторая статья относится к блогу Майкрософт от Jam ie Rodriguez, в котором есть три архивные статьи: Drag and Drop End to End , Drag and Drop Part 2 и Перетаскивание Часть 3 .

Выбор столбца - это собственный элемент управления, который можно прикрепить к заголовку сетки (xaml и код, показанный ниже). Иногда событие drop вызывается, иногда это не так. Что приводит к тому, что событие drop не вызывается? Другая наша проблема - когда происходит сбой, пользовательский интерфейс перестает отвечать, что может вызвать это? Если мы отключим, как показано ниже, пользовательский визуал, то все будет работать так, как должно:

        if ( e.LeftButton == MouseButtonState.Pressed )
        {
            Trace ( "Chooser_PreviewMouseMove enter" );

            var listBoxItem = FindVisualParent<ListBoxItem> ( ( ( DependencyObject ) e.OriginalSource ) );

            if ( listBoxItem != null )
            {
                var dragItem = listBoxItem.DataContext as IColumnSetting;
                if ( dragItem != null )
                {
                    //CreateDragDropWindow ( dragItem );

                    DragDrop.DoDragDrop ( listBoxItem, listBoxItem.DataContext, DragDropEffects.Move );

                    //CloseDragDropWindow ();

                }
            }
          }

            Trace ( "Chooser_PreviewMouseMove exit" );

У нас есть настройка столбца:

public interface IColumnSetting
{
   public string Header
   { get; set; }
}

public class ColumnSetting : IColumnSetting
{
   public string Header
   { get; set; }
}

, который используется средством выбора столбцов , Затем у нас есть xaml и код для пользовательского элемента управления:

<UserControl 
  x:Name="root"
  x:Class="ColumnApp.ColumnChooser"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" >

<Grid>
    <ListBox 
        x:Name="Chooser"
        BorderThickness="0"
        ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, 
                              Path=ColumnSettings}" >


        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox 
                    Content="{Binding Header, Mode=OneWay}" 
                    IsChecked="{Binding IsVisible, Mode=TwoWay}" />

            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>



</Grid>

и код выбора столбца позади:

public partial class ColumnChooser : UserControl
{

    #region Mouse Handling

    [StructLayout ( LayoutKind.Sequential )]
    private struct Win32Point
    {
        public Int32 X;
        public Int32 Y;
    };

    [DllImport ( "user32.dll" )]
    private static extern bool GetCursorPos ( ref Win32Point pt );

    public Point GetMousePosition ()
    {
        Win32Point mouse = new Win32Point ();
        GetCursorPos ( ref mouse );

        return new Point () { X = ( double ) mouse.X, Y = (double) mouse.Y };
    }


    #endregion


    #region 

    public ColumnChooser ()
    {
        try
        {
            InitializeComponent ();

            Chooser.PreviewMouseMove += Chooser_PreviewMouseMove;

            var style = new Style ( typeof ( ListBoxItem ) );
            style.Setters.Add ( new Setter ( ListBoxItem.AllowDropProperty, true ) );

            style.Setters.Add (
                    new EventSetter (
                        ListBoxItem.DropEvent,
                        new DragEventHandler ( Chooser_Drop ) ) );


            style.Setters.Add (
                new EventSetter (
                    ListBoxItem.GiveFeedbackEvent,
                    new GiveFeedbackEventHandler ( Chooser_GiveFeedback ) ) );

            Chooser.ItemContainerStyle = style;
        }
        catch ( Exception ex )
        {
            Trace ( "FAILED to create column chooser" );
        }
    }

    #endregion



    #region Properties


    #endregion



    #region Dependency Properties

    public ObservableCollection<IColumnSetting> ColumnSettings
    {
        get { return ( ObservableCollection<IColumnSetting> ) GetValue ( ColumnSettingsProperty ); }
        set
        {
            SetValue ( ColumnSettingsProperty, value );
        }
    }



    public static readonly DependencyProperty ColumnSettingsProperty =
        DependencyProperty.Register ( "ColumnSettings", typeof ( ObservableCollection<IColumnSetting> ), typeof ( ColumnChooser ),
                                       new PropertyMetadata ( null ) );

    static void OnColumnSettingsChanged ( DependencyObject obj, DependencyPropertyChangedEventArgs e )
    {
        var model = obj as ColumnChooser;
        if ( model == null )
            return;

        try
        {
            var columnSettings = model.ColumnSettings;
            if ( columnSettings == null || columnSettings.Count == 0 )
            {
                int i = 0;
                i++;
            }

            //model.Chooser.ItemsSource = columnSettings;
        }
        catch ( Exception ex )
        {
            LogProvider.Logger.LogException ( "Error OnCurrentGageChanged", ex );
        }

    }

    #endregion


    #region Support Methods


    private T FindVisualParent<T> ( DependencyObject child )
                where T : DependencyObject
    {
        var parentObject = VisualTreeHelper.GetParent ( child );
        if ( parentObject == null )
            return null;
        T parent = parentObject as T;
        if ( parent != null )
            return parent;
        return FindVisualParent<T> ( parentObject );
    }

    #endregion

    #region Drap And Drop Handlers

    Size DragSz
    { get; set; }

    Window DragDropWindow
    { get; set; }


    static Point PointToPixel ( Point p )
    {
        var t = PresentationSource.FromVisual ( Application.Current.MainWindow ).CompositionTarget.TransformFromDevice;
        return t.Transform ( p );
    }

    public FrameworkElement CreateDragVisual ( IColumnSetting columnSetting )
    {
        if ( columnSetting == null )
            throw new ArgumentNullException ( "columnSetting requred" );
        var stackPanel = new StackPanel ();
        if ( stackPanel == null )
            throw new NullReferenceException ( "FAILED to create stack panel" );

        var textBlock = new ThemeTextBlock ();
        if ( textBlock == null )
            throw new NullReferenceException ( "FAILED to create text block" );

        textBlock.Text = columnSetting.Header;

        stackPanel.Children.Add ( textBlock );

        return stackPanel;
    }

    private void CreateDragDropWindow ( IColumnSetting columnSetting )
    {
        Trace ( "CreateDragDropWindow enter" );

        CloseDragDropWindow ();

        DragDropWindow = new Window ();
        if ( DragDropWindow == null )
            throw new NullReferenceException ( "FAILED to create DragDropWindow" );

        DragDropWindow.WindowStyle = WindowStyle.None;
        DragDropWindow.AllowsTransparency = true;
        DragDropWindow.AllowDrop = false;
        DragDropWindow.Background = null;
        DragDropWindow.IsHitTestVisible = false;
        DragDropWindow.SizeToContent = SizeToContent.WidthAndHeight;
        DragDropWindow.Topmost = true;
        DragDropWindow.ShowInTaskbar = false;

        var dragElement = CreateDragVisual ( columnSetting );

        dragElement.Measure ( new Size ( double.PositiveInfinity, double.PositiveInfinity ) );
        dragElement.Arrange ( new Rect ( 0, 0, 150, 15 ) );

        DragSz = new Size ( dragElement.RenderSize.Width, dragElement.RenderSize.Height );
        if ( DragSz == null )
            throw new NullReferenceException ( "FAILED to create DragSz" );

        this.DragDropWindow.Content = dragElement;

        var position = GetMousePosition ();
        var cursorPt = PointToPixel ( position );

        DragDropWindow.Left = cursorPt.X - ( DragSz.Width / 4 );
        DragDropWindow.Top = cursorPt.Y - ( DragSz.Height / 2 );

        Trace ( "CreateDragDropWindow DragDropWindow.Left: " + DragDropWindow.Left + " DragDropWindow.Top: " + DragDropWindow.Top );
        Trace ( "CreateDragDropWindow cursorPt X: " + cursorPt.X + " cursorPt.Y: " + cursorPt.Y );


        DragDropWindow.Show ();

        Trace ( "CreateDragDropWindow exit" );

    }


    private void CloseDragDropWindow ()
    {
        if ( DragDropWindow == null )
            return;

        Trace ( "CloseDragDropWindow enter" );

        DragDropWindow.Close ();
        DragDropWindow = null;

        Trace ( "CloseDragDropWindow exit" );
    }


    public Rect GetControlPosition ( FrameworkElement element )
    {
        var absolutePos = element.PointToScreen ( new System.Windows.Point ( 0, 0 ) );

        return new Rect ( absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight );
    }

    private void Chooser_PreviewMouseMove ( object sender, MouseEventArgs e )
    {
        var lb = sender as ListBox;
        if ( lb == null )
            return;

        if ( e.LeftButton == MouseButtonState.Pressed )
        {
            Trace ( "Chooser_PreviewMouseMove enter" );

            var listBoxItem = FindVisualParent<ListBoxItem> ( ( ( DependencyObject ) e.OriginalSource ) );

            if ( listBoxItem != null )
            {
                var dragItem = listBoxItem.DataContext as IColumnSetting;
                if ( dragItem != null )
                {
                    CreateDragDropWindow ( dragItem );

                    DragDrop.DoDragDrop ( listBoxItem, listBoxItem.DataContext, DragDropEffects.Move );

                    CloseDragDropWindow ();

                }
            }

            Trace ( "Chooser_PreviewMouseMove exit" );

        }
    }

    private void Chooser_GiveFeedback ( object sender, GiveFeedbackEventArgs e )
    {
        Trace ( "Chooser_GiveFeedback enter" );

        if ( DragDropWindow == null )
            return;

        var position = GetMousePosition ();
        var cursorPt = PointToPixel ( position );

        Trace ( "Chooser_GiveFeedback Move DragDropWindow" );
        Trace ( "Chooser_GiveFeedback cursorPt X: " + cursorPt.X + " cursorPt.Y: " + cursorPt.Y );

        DragDropWindow.Left = cursorPt.X - ( DragSz.Width / 4 );
        DragDropWindow.Top = cursorPt.Y - ( DragSz.Height / 2 );

        e.Handled = true;

        Trace ( "Chooser_GiveFeedback DragDropWindow.Left: " + DragDropWindow.Left + " DragDropWindow.Top: " + DragDropWindow.Top );
        Trace ( "Chooser_GiveFeedback Moved DragDropWindow" );

        Trace ( "Chooser_GiveFeedback exit" );
    }




    private void Chooser_Drop ( object sender, DragEventArgs e )
    {
        Trace ( "Chooser_Drop enter" );

        var listBoxItem = sender as ListBoxItem;
        if ( listBoxItem == null )
            return;

        var item = e.Data.GetData ( typeof ( Gt.BaseDefs.ViewSettings.ColumnSetting ) );
        if ( item != null )
        {
            Trace ( "Chooser_Drop moving column" );

            var dragItem = item as IColumnSetting;
            var dropItem = listBoxItem.DataContext as IColumnSetting;

            int dragIndex = ColumnSettings.IndexOf ( dragItem );
            int dropIndex = ColumnSettings.IndexOf ( dropItem );

            Move ( dragItem, dragIndex, dropIndex );


            Trace ( "Chooser_Drop moved column" );
        }

        Trace ( "Chooser_Drop exit" );


    }

    private void Move ( IColumnSetting dragItem, int dragIndex, int dropIndex )
    {

        if ( dragIndex < dropIndex )
        {
            ColumnSettings.Insert ( dropIndex + 1, dragItem );
            ColumnSettings.RemoveAt ( dragIndex  );
        }
        else
        {
            if ( dragIndex < ColumnSettings.Count + 1 )
            {
                ColumnSettings.RemoveAt ( dragIndex );
                ColumnSettings.Insert ( dropIndex, dragItem );
            }
        }
    }


    #endregion

    #region ITrace

    public void Trace ( string msg )
    {
       Debug.WriteLine ( msg );
    }

    #endregion


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