0

I have requirement in which i need to show smooth scrolling text with some GIF Images and jpeg or mediaelement on a ticker. However, since this involves lot of CPU cycles for the main UI thread, i planned to create the ticker control on another thread with a dispatcher and then host this ticker on the form. However, i am getting a cross-thread exception that thread cannot access the control as another thread owns it.

I have done similar thing in Delphi, wherein i have set the ticker parent with SetWindowParent();

my code is as below

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        TickerControlContainer loclContainer = new TickerControlContainer(this);
    }
}

public class TickerControlContainer
{
    private MainWindow f_Window;

    private void CreateControl()
    {
        TickerControl loclControl = new TickerControl();
        loclControl.InitializeComponent();

        f_Window.Dispatcher.Invoke((MethodInvoker)delegate { AddControl(loclControl); });
    }

    private void AddControl(TickerControl piclControl)
    {
        f_Window.Content = piclControl;
        **// exception occurs**
    }

    public TickerControlContainer(MainWindow piclWindow)
    {
        f_Window = piclWindow;
        ManualResetEvent loclResetEvent = new ManualResetEvent(false);
        Dispatcher loclDispatcher = null;
        Thread th1 = new Thread(new ThreadStart(() =>
            {
                loclDispatcher = Dispatcher.CurrentDispatcher;

                loclResetEvent.Set();
                Dispatcher.Run();
            }));

        th1.SetApartmentState(ApartmentState.STA);
        th1.Start();
        loclResetEvent.WaitOne();
        loclDispatcher.BeginInvoke((MethodInvoker)delegate { CreateControl(); });
    }
}

Do i need to put a contentcontrol or something on my form, instead of setting as the content of the form.

This is just a sample that i am trying to do. Please help.

Rahul W
  • 833
  • 11
  • 26

2 Answers2

0

There's only one UI thread in WPF/.NET (though I think different windows can run on separate threads), so I don't really think there's an easy way to do what you're trying to do here.

Is it the animation that's taking up a lot of CPU, or are you doing a lot of processing in addition to the animation? If so, I would offload the calculations to a background thread and then invoke it to the UI thread when complete.

Matt
  • 2,682
  • 1
  • 17
  • 24
0

I was able to host control created on another thread on my main window, but before creating the control, the Window has to be shown atleast once.

using...


namespace WpfMultiDispatcherUpdates
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    private void btnCreateControl_Click(object sender, RoutedEventArgs e)
    {
        TickerControlContainer loclContainer = new TickerControlContainer(this);
    }
}

public class TickerControlContainer
{
    private MainWindow f_Window;

    [DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
    private static extern IntPtr SetParent(IntPtr hwndChild, IntPtr hwndParent);

    private void CreateControl(HwndSource piclSource)
    {
        TickerControl loclControl = new TickerControl();
        loclControl.InitializeComponent();

        Window loclHostWindow = new Window();
        loclHostWindow.WindowStyle = WindowStyle.None;

        loclHostWindow.WindowState = WindowState.Normal;
        loclHostWindow.Left = 0;
        loclHostWindow.Top = 0;

        loclHostWindow.ShowInTaskbar = false;
        loclHostWindow.Content = loclControl;
        loclHostWindow.ShowActivated = true;
        loclControl.Height = 200;
        loclControl.Width = (double)f_Window.Dispatcher.Invoke(new Func<double>(() => { return f_Window.Width; }));
        piclSource.SizeToContent = SizeToContent.WidthAndHeight;
        loclHostWindow.SizeToContent = SizeToContent.WidthAndHeight;
        loclHostWindow.Show();
        SetParent(new WindowInteropHelper(loclHostWindow).Handle, piclSource.Handle);
    }

    private void AddControl(TickerControl piclControl)
    {
        f_Window.Content = new ContentControl() { Content = piclControl };
    }

    public TickerControlContainer(MainWindow piclWindow)
    {
        f_Window = piclWindow;
        ManualResetEvent loclResetEvent = new ManualResetEvent(false);
        Dispatcher loclDispatcher = null;
        Thread th1 = new Thread(new ThreadStart(() =>
            {
                loclDispatcher = Dispatcher.CurrentDispatcher;

                loclResetEvent.Set();
                try
                {
                    Dispatcher.Run();
                }
                catch (Exception E)
                {
                    System.Windows.MessageBox.Show(E.Message);
                }
            }));

        th1.SetApartmentState(ApartmentState.STA);
        th1.Start();
        loclResetEvent.WaitOne();
        try
        {
            HwndSourceParameters loclSourceParams = new HwndSourceParameters();
            loclSourceParams.WindowStyle = 0x10000000 | 0x40000000;
            loclSourceParams.SetSize((int)piclWindow.Width, 200);
            loclSourceParams.SetPosition(0, 20);
            loclSourceParams.UsesPerPixelOpacity = true;
            loclSourceParams.ParentWindow = new WindowInteropHelper(piclWindow).Handle;

            HwndSource loclSource = new HwndSource(loclSourceParams);
            loclSource.CompositionTarget.BackgroundColor = Colors.Transparent;

            loclDispatcher.BeginInvoke((MethodInvoker)delegate { CreateControl(loclSource); });
        }
        catch (Exception E)
        {
            System.Windows.MessageBox.Show(E.Message);
        }
    }
}
}

However, i need to add the Resize events and resize my control when the MainWindow height and width changes. The values are hardcoded for testing purposes. Now, the drawing on the child control does not affect my Main Window, but the complexity of controlling my child control is more..

The host should not have any other child controls in the area where we host this threaded control.

Rahul W
  • 833
  • 11
  • 26