2

だからここに私が取り組んでいるシナリオがあります:

現在、ItemsControl/ListView として表されている優先度リストがあり、優先度アイテムの監視可能なコレクションにバインドされています。要素の並べ替えのために、視覚的に厳密に制限された垂直方向のドラッグを提供したいと考えています。

したがって、ドラッグ アドナーはなく、水平方向の動きはなく、垂直方向の動きのみです。リスト項目が別の項目の中間点を通過すると、アニメーションによって「位置が入れ替わる」必要があります。これは、コンテナー自体で mousedown/mousemove を操作することで実行できると確信しており、レンダリング変換を適用してこれを実行できると確信していますが、私の理想的なソリューションには次の 2 つのコンポーネントがあります。

  1. この機能は、WPF の対話動作としてアタッチできます。

  2. システムは MVVM フレンドリーであり、重要なコード ビハインドは必要ありません。

これは行われましたか?どこで見つけることができますか?そうでない場合、これを行うためにすべてのビットをまとめるにはどうすればよいでしょうか?

編集:バウンティが開かれました。コメントで直接質問してください。できるだけ早く返信します。

4

2 に答える 2

6

そしてコーデに…

マークアップ:

<AdornerDecorator Margin="5">
    <ListBox x:Name="_listBox" Width="300" 
              HorizontalAlignment="Left"
              ItemsSource="{Binding Path=Items}" 
          AllowDrop="True" Drop="listBox_Drop">
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <EventSetter Event="ListBoxItem.DragOver"  Handler="listBoxItem_DragOver"/>
                <EventSetter Event="ListBoxItem.Drop" Handler="listBoxItem_Drop"/>
                <EventSetter Event="ListBoxItem.MouseMove" Handler="listBoxItem_MouseMove"/>
                <EventSetter Event="ListBoxItem.MouseDown" Handler="listBoxItem_MouseDown"/>
                <EventSetter Event="ListBoxItem.PreviewMouseDown" Handler="listBoxItem_MouseDown"/>
                <Setter Property="AllowDrop" Value="True"/>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>
</AdornerDecorator>

コードビハインド:

private bool _isDragging;

    private void listBox_MouseDown(object sender, MouseButtonEventArgs e)
    {
        _isDragging = false;
    }

    Adorner _adorner;

    private void listBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (!_isDragging && e.LeftButton == MouseButtonState.Pressed)
        {
            _isDragging = true;

            if (_listBox.SelectedValue != null)
            {
                DragDrop.DoDragDrop(_listBox, _listBox.SelectedValue,
                   DragDropEffects.Move);
            }

        }
    }




private ListBoxItem FindlistBoxItem(DragEventArgs e)
    {
        var visualHitTest = VisualTreeHelper.HitTest(_listBox, e.GetPosition(_listBox)).VisualHit;

        ListBoxItem listBoxItem = null;

        while (visualHitTest != null)
        {
            if (visualHitTest is ListBoxItem)
            {
                listBoxItem = visualHitTest as ListBoxItem;

                break;
            }
            else if (visualHitTest == _listBox)
            {
                Console.WriteLine("Found listBox instance");
                return null;
            }

            visualHitTest = VisualTreeHelper.GetParent(visualHitTest);
        }

        return listBoxItem;
    }

    void ClearAdorner()
    {
        if (_adorner != null)
        {
            var adornerLayer = AdornerLayer.GetAdornerLayer(_listBox);
            adornerLayer.Remove(_adorner);
        }
    }

    private void listBox_DragOver(object sender, DragEventArgs e)
    {
        e.Effects = DragDropEffects.Move;

        ClearAdorner();

        var listBoxItem = FindlistBoxItem(e);

        if (listBoxItem == null || listBoxItem.DataContext == _listBox.SelectedItem) return;

        if (IsInFirstHalf(listBoxItem, e.GetPosition(listBoxItem)))
        {
            var adornerLayer = AdornerLayer.GetAdornerLayer(_listBox);
            _adorner = new DropBeforeAdorner(listBoxItem);
            adornerLayer.Add(_adorner);
        }
        else if (IsInLastHalf(listBoxItem, e.GetPosition(listBoxItem)))
        {
            var adornerLayer = AdornerLayer.GetAdornerLayer(_listBox);
            _adorner = new DropAfterAdorner(listBoxItem);
            adornerLayer.Add(_adorner);
        }

    }

    private void listBox_Drop(object sender, DragEventArgs e)
    {
        if (_isDragging)
        {
            _isDragging = false;
            ClearAdorner();

            var listBoxItem = FindlistBoxItem(e);

            if (listBoxItem == null || listBoxItem.DataContext == _listBox.SelectedItem) return;

            var drop = _listBox.SelectedItem as Export.Domain.Components.Component;
            var target = listBoxItem.DataContext as Export.Domain.Components.Component;

            var listBoxItem = GetlistBoxItemControl(listBoxItem);

            if (IsInFirstHalf(listBoxItem, e.GetPosition(listBoxItem)))
            {
                var vm = this.DataContext as ComponentlistBoxModel;
                vm.DropBefore(drop, target);
            }                
            else if (IsInLastHalf(listBoxItem, e.GetPosition(listBoxItem)))
            {
                var vm = this.DataContext as ComponentlistBoxModel;
                vm.DropAfter(drop, target);
            }
        }
    }



    public static bool IsInFirstHalf(FrameworkElement container, Point mousePosition)
    {
        return mousePosition.Y < (container.ActualHeight/2);
    }

    public static bool IsInLastHalf(FrameworkElement container, Point mousePosition)
    {
        return mousePosition.Y > (container.ActualHeight/2);
    }

私のコード ビハインドが具体的にビューモデルをタイプ別に参照しているという事実が気に入らないかもしれませんが、それは仕事を成し遂げました。それは迅速かつ簡単で、技術的には MVVM パターンを壊すことはありません。ロジックは引き続きビューモデルに任せます。

追加 1 アニメーションは、おそらく探している効果を提供します。私の実装では、ドロップ時にスワップが発生します。ただし、アドナーを使用してドラッグ時にスワップを発生させることで、アニメーション効果を実現できます。ドラッグ イベントは、コレクション内のオブジェクトの装飾位置とインデックスを更新します。

于 2012-10-25T22:28:10.973 に答える