Darren Ng
Darren Ng

Reputation: 373

Slow down binding update?

My application contains many ListBox. Each ListBox contains many ListBoxItem. What I'm trying to enforce, is that the ListBoxItem's MaxWidth is always 80% of the ListBox's Width. Currently, I'm binding it like this:

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="MaxWidth" Value="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType=ListBox}, Converter={StaticResource MessageWidthConverter}}"/>

It works, but unfortunately it made resizing the application very very slow. CPU usage is more than 50% on a i7 2600 during re-sizing, and I understand it's due to the sheer amount of computation of the new MaxWidth of the thousands of ListBoxItem.

Is there any way to do this without causing the huge slowdown during resizing, or any way to ask the binding to update not so frequently?

Upvotes: 0

Views: 166

Answers (1)

user3596113
user3596113

Reputation: 878

We had a similiar problem when hosting a Wpf control in a WinForm. Best solution for us was to Suspend the layout of the control like this in the OnResize Event:

protected override void OnResize(EventArgs e)
{
    // supress flickering if dockstate is float
    if (DockHandler.DockState == WeifenLuo.WinFormsUI.Docking.DockState.Float) {
        WpfInteropHelper.Suspend(this);
    }
    base.OnResize(e);
    if (DockHandler.DockState == WeifenLuo.WinFormsUI.Docking.DockState.Float) {
        WpfInteropHelper.Resume(this);
    }
}

Therefore we added a helper class:

/// <summary>
/// Class containing helper functions for wpf interoperability 
/// </summary>
public static class WpfInteropHelper
{
    private const int WMSETREDRAW = 0x000B;

    /// <summary>
    /// Suspends the specified control.
    /// </summary>
    /// <param name="control">The control.</param>
    public static void Suspend(Control control)
    {
        Message msgSuspendUpdate = Message.Create(control.Handle, WMSETREDRAW, IntPtr.Zero, IntPtr.Zero);

        NativeWindow window = NativeWindow.FromHandle(control.Handle);
        window.DefWndProc(ref msgSuspendUpdate);
    }

    /// <summary>
    /// Resumes the specified control.
    /// </summary>
    /// <param name="control">The control.</param>
    public static void Resume(Control control)
    {
        control.Visible = false;
        var wparam = new IntPtr(1);
        Message msgResumeUpdate = Message.Create(control.Handle, WMSETREDRAW, wparam, IntPtr.Zero);
        NativeWindow window = NativeWindow.FromHandle(control.Handle);
        if (window != null) {
            window.DefWndProc(ref msgResumeUpdate);
        }
        control.Invalidate();
        control.Visible = true;
    }
}

I hope you can use this for your WPF control aswell.

Upvotes: 1

Related Questions