我要求我需要在自动收报机上显示带有一些GIF图像和jpeg或mediaelement的平滑滚动文本。但是,由于这涉及主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(); });
}
}
我是否需要在表单上放置内容控件或其他内容,而不是将其设置为表单的内容。
这只是我想要做的一个例子。请帮忙。
答案 0 :(得分:0)
WPF / .NET中只有一个UI线程(虽然我认为不同的窗口可以在不同的线程上运行),所以我真的不认为有一种简单的方法可以做你想做的事情。
动画占用了大量的CPU,还是除了动画之外还要进行大量的处理?如果是这样,我会将计算卸载到后台线程,然后在完成时将其调用到UI线程。
答案 1 :(得分:0)
我能够在我的主窗口上托管在另一个线程上创建的控件,但在创建控件之前,必须至少显示一次Window。
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);
}
}
}
}
但是,当MainWindow高度和宽度发生变化时,我需要添加Resize事件并调整我的控件大小。为了测试目的,这些值是硬编码的。现在,子控件上的绘图不会影响我的主窗口,但控制我的子控件的复杂性更多..
主机不应该在我们托管此线程控件的区域中有任何其他子控件。