wpf 中主线程控件之上的线程代码控件



我有要求,我需要在股票代号上显示带有一些 GIF 图像和 jpeg 或媒体元素的平滑滚动文本。但是,由于这涉及主 UI 线程的大量 CPU 周期,因此我计划在另一个具有调度程序的线程上创建代码控件,然后在窗体上托管此代码。但是,我收到一个跨线程异常,线程无法访问该控件,因为另一个线程拥有它。

我在Delphi中做了类似的事情,其中我用SetWindowParent()设置了股票代父级;

我的代码如下

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(); });
    }
}

我是否需要在我的表单上放置内容控件或其他内容,而不是设置为表单的内容。

这只是我正在尝试做的一个示例。请帮忙。

WPF/.NET 中只有一个 UI 线程(尽管我认为不同的窗口可以在不同的线程上运行),所以我真的不认为有一种简单的方法来执行您在这里尝试做的事情。

是动画占用

了大量CPU,还是除了动画之外还进行了大量处理? 如果是这样,我会将计算卸载到后台线程,然后在完成后将其调用到 UI 线程。

我能够在主窗口上托管在另一个线程上创建的控件,但在创建控件之前,该窗口必须至少显示一次。

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);
        }
    }
}
}

但是,我需要添加 调整大小 事件并在主窗口高度和宽度更改时调整控件大小。这些值是硬编码的,用于测试目的。现在,子控件上的绘图不会影响我的主窗口,但控制子控件的复杂性更高。

宿主在我们承载此线程控件的区域中不应有任何其他子控件。

最新更新