C# wpf中主线程控件顶部的线程化ticker控件

C# wpf中主线程控件顶部的线程化ticker控件,c#,wpf,multithreading,dispatcher,C#,Wpf,Multithreading,Dispatcher,我有一个要求,我需要显示一些GIF图像和jpeg或mediaelement的股票上平滑滚动的文本。但是,由于这涉及到主UI线程的大量CPU周期,因此我计划使用dispatcher在另一个线程上创建ticker控件,然后在窗体上托管该ticker。但是,我得到了一个跨线程异常,该线程无法访问该控件,因为另一个线程拥有它 我在Delphi中也做过类似的事情,我用SetWindowParent()设置了ticker父对象 我的代码如下 public partial class MainWindow :

我有一个要求,我需要显示一些GIF图像和jpeg或mediaelement的股票上平滑滚动的文本。但是,由于这涉及到主UI线程的大量CPU周期,因此我计划使用dispatcher在另一个线程上创建ticker控件,然后在窗体上托管该ticker。但是,我得到了一个跨线程异常,该线程无法访问该控件,因为另一个线程拥有它

我在Delphi中也做过类似的事情,我用SetWindowParent()设置了ticker父对象

我的代码如下

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(); });
    }
}
我是否需要在窗体上放置contentcontrol或其他内容,而不是设置为窗体的内容


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

在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);
        }
    }
}
}
使用。。。
命名空间WpfMultiDispatcherUpdates
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
私有void btnCreateControl_单击(对象发送方,路由目标)
{
TickerControlContainer LocalContainer=新的TickerControlContainer(本);
}
}
公共类TickerControl容器
{
专用主窗口f_窗口;
[DllImport(“user32.dll”,SetLastError=false,ExactSpelling=false)]
私有静态外部IntPtr SetParent(IntPtr hwndChild,IntPtr hwndpparent);
私有void CreateControl(HwndSource piclSource)
{
TickerControl loclControl=新的TickerControl();
LocalControl.InitializeComponent();
Window loclHostWindow=新窗口();
loclHostWindow.WindowStyle=WindowStyle.None;
loclHostWindow.WindowsState=WindowsState.Normal;
loclHostWindow.Left=0;
loclHostWindow.Top=0;
loclHostWindow.ShowInTaskbar=false;
loclHostWindow.Content=loclControl;
loclHostWindow.ShowActivated=true;
LOCL控制高度=200;
loclControl.Width=(double)f_Window.Dispatcher.Invoke(newfunc(()=>{return f_Window.Width;}));
piclSource.SizeToContent=SizeToContent.WidthAndHeight;
loclHostWindow.SizeToContent=SizeToContent.Width和Height;
loclHostWindow.Show();
SetParent(新的WindowInteropHelper(loclHostWindow.Handle,piclSource.Handle);
}
专用无效添加控制(TickerControl piclControl)
{
f_Window.Content=newcontentcontrol(){Content=piclControl};
}
公共票务控制容器(主窗口piclWindow)
{
f_Window=piclWindow;
ManualResetEvent LocalResetEvent=新的ManualResetEvent(错误);
调度程序loclDispatcher=null;
线程th1=新线程(新线程开始(()=>
{
loclDispatcher=Dispatcher.CurrentDispatcher;
loclResetEvent.Set();
尝试
{
Dispatcher.Run();
}
捕获(例外E)
{
System.Windows.MessageBox.Show(E.Message);
}
}));
th1.SetApartmentState(ApartmentState.STA);
th1.Start();
loclResetEvent.WaitOne();
尝试
{
HwndSourceParameters loclSourceParams=新的HwndSourceParameters();
loclSourceParams.WindowsStyle=0x10000000 | 0x40000000;
loclSourceParams.SetSize((int)微微窗宽,200);
loclSourceParams.SetPosition(0,20);
loclSourceParams.UseSperpixeLocapacity=true;
loclSourceParams.ParentWindow=新窗口Interophelper(piclWindow).Handle;
HwndSource loclSource=新的HwndSource(loclSourceParams);
loclSource.CompositionTarget.BackgroundColor=颜色。透明;
BeginInvoke((MethodInvoker)委托{CreateControl(LocalSource);});
}
捕获(例外E)
{
System.Windows.MessageBox.Show(E.Message);
}
}
}
}
但是,当主窗口的高度和宽度发生变化时,我需要添加调整大小事件并调整控件的大小。出于测试目的,这些值被硬编码。现在,子控件上的绘图不会影响我的主窗口,但控制子控件的复杂性更大

在托管此线程控件的区域中,主机不应具有任何其他子控件