1

ドラッグアンドドロップ機能が必要なため、カスタムTreeViewクラスを使用しています。ドラッグしたアイテムがどこに移動するかをユーザーに示すために、ツリービューに線を描画しています。「ドロップターゲット」が変更されるたびに、ツリービューを再描画する必要があるため、これにより多くの目に見えるちらつきが発生します(以前に描画されたものをすべてクリーンアップするため)

残念ながら、TreeViewにはDoubleBufferedオプションはありません。

そこで、私はこの解決策について考えました。ツリービューの上にある、それ自体にペイントできる非表示のコントロールですが、すべてのマウスイベントを通過させ、フォーカスを取得しません。そのコントロールにペイントして、ちらつきを防ぐことができました。

しかし、私はそれをどのように行うかについて全く手がかりがありません。パネルの色を透明に設定できることは知っていますが、クリックしてもかまいません...

PS:私は簡単な方法をとることになりました。つまり、以前に描いたものを白い色で再描画し、コントロールを無効にすることなく、新しい選択インジケーターを黒で描画しました。これによりちらつきがなくなりました。ただし、StackOverflowでは回答を選択する必要があるため、最も適切と思われる回答を選択します...おそらく...

4

5 に答える 5

3

Locus Effectライブラリを見ると、クリックスルー可能な透明なトップレベルウィンドウがペイントされています。

ソリューションの中心では、これは次のようなウィンドウプロシージャをオーバーライドするウィンドウによって実行されます。

protected override void WndProc(ref Message m)
{
    // Do not allow this window to become active - it should be "transparent" 
    // to mouse clicks i.e. Mouse clicks pass through this window
    if ( m.Msg == Win32Constants.WM_NCHITTEST )
    {
        m.Result = new IntPtr( Win32Constants.HTTRANSPARENT );
        return;
    }

    base.WndProc( ref m ) ;
}

存在するWM_NCHITTESTこと0x0084と存在するHTTRANSPARENTこと-1

このソリューションが子コントロールでも機能するかどうかはわかりませんが、試してみる価値があるかもしれません。コントロールを派生させて、をオーバーライドするだけWndProcです。

于 2012-04-07T11:12:44.757 に答える
3
        protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x84)
        {
            m.Result= new IntPtr(-1);
            return;
        }
        base.WndProc(ref m);
    }

2012年に機能するものです...

于 2013-01-14T21:59:21.807 に答える
2

このような透明なキャンバスでさえ、背景を再描画する必要があります(背後にあるものも含まれます)。おそらくこれにはいくつかのハックがありますが、コンポーネントのちらつきの問題に遭遇するたびに、コンポーネント(またはカスタム)のダブルバッファリングを活用するなど、本当に満足のいく解決策はありませんでした。このようなライブグラフィックインタラクションがアプリケーションの必要な部分になるとき、私は常に、グラフィックを「正しい方法」で実行するものに移動することが最善の選択肢であることに気づきました。WPF、XNA、またはDirectXは、おそらくこの問題に対する最良の答えです。WPFは、この種の1つのイベント->多くのコンポーネントのパラダイムをコーディングするのをはるかに簡単にするルーティングされたイベントのようなものも追加します。

これは、winformsアプリケーションでWPF相互運用性コンポーネントを使用する例です。

1)フォームに新しいElementHostを追加します(elementHost1ここではこれを呼び出しました)

2)プロジェクトに新しいWPF UserControlを追加します(私はそれを呼び出しましたTreeCanvas

XAML

<UserControl x:Class="WindowsFormsApplication1.TreeCanvas"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="300" Height="300">
<Grid>
    <Canvas Name="Canvas1">
        <TreeView Canvas.Left="0" Canvas.Top="0" Height="300" Name="TreeView1" Width="300" />
    </Canvas>
</Grid>

TreeCanvasのコードビハインドには何も必要ありません。生成されたコードはInitializeComponent();、今のところ必要なものだけです。

そしてあなたのフォームコード

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        //make a new TreeCanvas

        private TreeCanvas MyTreeCanvas = new TreeCanvas();

        public Form1()
        {
            InitializeComponent();
            //attach the TreeCanvas component to the element host
            this.Width = 400;
            this.Height = 400;
            elementHost1.Child = MyTreeCanvas;
            elementHost1.Location = new System.Drawing.Point(30, 30);
            elementHost1.Height = 300;
            elementHost1.Width = 300;

            // Just adding some random stuff to the treeview
            int i = 0;
            int j = 0;
            for (i = 0; i <= 10; i++)
            {
                TreeViewItem nitm = new TreeViewItem();
                nitm.Header = "Item " + Convert.ToString(i);
                MyTreeCanvas.TreeView1.Items.Add(nitm);
                for (j = 1; j <= 3; j++)
                {
                    TreeViewItem itm = (TreeViewItem)MyTreeCanvas.TreeView1.Items[i];
                    itm.Items.Add("Item " + Convert.ToString(j));
                }
            }

            //Draw a line on the canvas with the treeview
            Line myLine = new Line();
            myLine.Stroke = System.Windows.Media.Brushes.Red;
            myLine.X1 = 1;
            myLine.X2 = 50;
            myLine.Y1 = 1;
            myLine.Y2 = 300;
            myLine.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            myLine.VerticalAlignment = VerticalAlignment.Center;
            myLine.StrokeThickness = 2;
            MyTreeCanvas.Canvas1.Children.Add(myLine);
        }

    }
}

これにより、キャンバス内のツリービューが表示され、その上にペイントして、下のツリービューをクリックして操作することができます(マウスのスクロールイベントなどを含む)。

行を直接クリックした場合、クリックは通過しません。同様に、マウスがキャンバス上の行を直接ホバリングしている場合、スクロールイベントなどは通過しませんが、ルーティングされたイベントを読み取ると、非常に簡単に配線できます。 TreeCanvasクラス内から一緒にそれらを。

于 2012-04-07T10:42:20.077 に答える
1

退屈だが効果的な答えを投稿します。TreeViewには、ノードを強調表示するための非常に優れたちらつきのない方法がすでにあります。DragOverイベントのイベントハンドラーを実装するだけで使用できます。このような:

    private void treeView_DragOver(object sender, DragEventArgs e) {
        var tree = (TreeView)sender;
        var pos = tree.PointToClient(new Point(e.X, e.Y));
        var hit = tree.HitTest(pos);
        if (hit.Node == null) e.Effect = DragDropEffects.None;
        else {
            tree.SelectedNode = hit.Node;
            tree.SelectedNode.Expand();        // Optional
            e.Effect = DragDropEffects.Copy;
        }
    }

コードでのTreeNode.Expand()の使用に注意してください。必要かどうかは質問からは明らかではありませんが、親が折りたたまれているために非表示になっているサブノードにアクセスする他の良い方法がないため、多くの場合必要になります。

于 2012-04-07T12:12:35.950 に答える
1

さて、あなたのオーバーレイは、それ自体をマウスのクリックと動きに結び付けるために焦点を合わせる必要があります。これを行うことで必ずしも問題が解決するかどうかはわかりません。

ただし、カスタムパネルを作成して透明にする場合は、プロパティを追加して、カスタムツリービューへのリンクを提供します。たとえば、onmouseclickハンドラーを追加します。この時点で、クリック手段を解釈し、パネルにデータを描画して、関連するカスタムツリービューのメソッドを呼び出すことができます。

したがって、インフラストラクチャの部分は非常に簡単で、ちらつきを取り除くことができますが、基本的には描画の量を最小限に抑えることであり、その頻度と量です。

透明なパネルがツリービューと同じくらい大きい場合は、とにかく全体を描画することになると思います。おそらく...rectを取るInvalidateの過負荷からより多くを得ることができるかもしれません...

于 2012-04-07T10:55:36.880 に答える