При использовании перетаскивания я могу заставить Treeview Разворачивать узел, над которым нависает пользователь?

Они могут закончиться, при попытке выполнить вызов виртуальной функции от конструктора или деструктора. Так как Вы не можете выполнить вызов виртуальной функции от конструктора, или деструктор (объект производного класса не был создан или был уже уничтожен), это называет версию базового класса, которая в случае чистой виртуальной функции, не существует.

(См. живую демонстрацию здесь )

class Base
{
public:
    Base() { doIt(); }  // DON'T DO THIS
    virtual void doIt() = 0;
};

void Base::doIt()
{
    std::cout<<"Is it fine to call pure virtual function from constructor?";
}

class Derived : public Base
{
    void doIt() {}
};

int main(void)
{
    Derived d;  // This will cause "pure virtual function call" error
}

12
задан Dave Clemmer 4 August 2011 в 21:23
поделиться

2 ответа

Вы можете использовать событие DragOver; он срабатывает неоднократно, пока вы перетаскиваете объект Открытие после задержки может быть выполнено очень легко с помощью двух дополнительных переменных, которые отмечают последний объект под курсором мыши и время. Нет необходимости в потоковой передаче или других трюках (lastDragDestination и lastDragDestinationTime в моем примере)

Из моего собственного кода:

TreeNode lastDragDestination = null;
DateTime lastDragDestinationTime;

private void tvManager_DragOver(object sender, DragEventArgs e)
{
    IconObject dragDropObject = null;
    TreeNode dragDropNode = null;

    //always disallow by default
    e.Effect = DragDropEffects.None;

    //make sure we have data to transfer
    if (e.Data.GetDataPresent(typeof(TreeNode)))
    {
        dragDropNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
        dragDropObject = (IconObject)dragDropNode.Tag;
    }
    else if (e.Data.GetDataPresent(typeof(ListViewItem)))
    {
        ListViewItem temp (ListViewItem)e.Data.GetData(typeof(ListViewItem));
        dragDropObject = (IconObject)temp.Tag;
    }

    if (dragDropObject != null)
    {
        TreeNode destinationNode = null;
        //get current location
        Point pt = new Point(e.X, e.Y);
        pt = tvManager.PointToClient(pt);
        destinationNode = tvManager.GetNodeAt(pt);
        if (destinationNode == null)
        {
            return;
        }

        //if we are on a new object, reset our timer
        //otherwise check to see if enough time has passed and expand the destination node
        if (destinationNode != lastDragDestination)
        {
            lastDragDestination = destinationNode;
            lastDragDestinationTime = DateTime.Now;
        }
        else
        {
            TimeSpan hoverTime = DateTime.Now.Subtract(lastDragDestinationTime);
            if (hoverTime.TotalSeconds > 2)
            {
                destinationNode.Expand();
            }
        }
    }
}
17
ответ дан 2 December 2019 в 19:54
поделиться

EDIT

I have a new solution, a bit far-fetched, but it works... It uses a DelayedAction class to handle delayed execution of an action on the main thread :

DelayedAction

public class DelayedAction<T>
{
    private SynchronizationContext _syncContext;
    private Action<T> _action;
    private int _delay;

    private Thread _thread;

    public DelayedAction(Action<T> action)
        : this(action, 0)
    {
    }

    public DelayedAction(Action<T> action, int delay)
    {
        _action = action;
        _delay = delay;
        _syncContext = SynchronizationContext.Current;
    }

    public void RunAfterDelay()
    {
        RunAfterDelay(_delay, default(T));
    }

    public void RunAfterDelay(T param)
    {
        RunAfterDelay(_delay, param);
    }

    public void RunAfterDelay(int delay)
    {
        RunAfterDelay(delay, default(T));
    }

    public void RunAfterDelay(int delay, T param)
    {
        Cancel();
        InitThread(delay, param);
        _thread.Start();
    }

    public void Cancel()
    {
        if (_thread != null && _thread.IsAlive)
        {
            _thread.Abort();
        }
        _thread = null;
    }

    private void InitThread(int delay, T param)
    {
        ThreadStart ts =
            () =>
            {
                Thread.Sleep(delay);
                _syncContext.Send(
                    (state) =>
                    {
                        _action((T)state);
                    },
                    param);
            };
        _thread = new Thread(ts);
    }
}

AutoExpandTreeView

public class AutoExpandTreeView : TreeView
{
    DelayedAction<TreeNode> _expandNode;

    public AutoExpandTreeView()
    {
        _expandNode = new DelayedAction<TreeNode>((node) => node.Expand(), 500);
    }

    private TreeNode _prevNode;
    protected override void OnDragOver(DragEventArgs e)
    {
        Point clientPos = PointToClient(new Point(e.X, e.Y)); 
        TreeViewHitTestInfo hti = HitTest(clientPos);
        if (hti.Node != null && hti.Node != _prevNode)
        {
            _prevNode = hti.Node;
            _expandNode.RunAfterDelay(hti.Node);
        }
        base.OnDragOver(e);
    }
}
0
ответ дан 2 December 2019 в 19:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: