我正在寻找找到here的库,这有助于在多个线程上呈现UI。该示例工作正常并按预期执行,但我想稍微修改它。
在示例中,将在后面的代码中定义/创建要在单独线程上呈现的可视元素。以下是一些示例代码:
XAML:
<Window x:Class="VisualTargetDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Microsoft.DwayneNeed.Controls;assembly=Microsoft.DwayneNeed"
Title="VisualTargetDemo"
SizeToContent="WidthAndHeight"
Loaded="OnLoaded"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<local:VisualWrapper Grid.Column="0" Width="200" Height="100" x:Name="Player1"/>
<local:VisualWrapper Grid.Column="1" Width="200" Height="100" x:Name="Player2"/>
<local:VisualWrapper Grid.Column="2" Width="200" Height="100" x:Name="Player3"/>
</Grid>
</Window>
代码隐藏:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Threading;
using Microsoft.DwayneNeed.Controls;
using Microsoft.DwayneNeed.Threading;
namespace VisualTargetDemo
{
public partial class Window1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Player1.Child = CreateMediaElementOnWorkerThread();
Player2.Child = CreateMediaElementOnWorkerThread();
Player3.Child = CreateMediaElementOnWorkerThread();
}
private HostVisual CreateMediaElementOnWorkerThread()
{
// Create the HostVisual that will "contain" the VisualTarget
// on the worker thread.
HostVisual hostVisual = new HostVisual();
// Spin up a worker thread, and pass it the HostVisual that it
// should be part of.
Thread thread = new Thread(new ParameterizedThreadStart(MediaWorkerThread));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start(hostVisual);
// Wait for the worker thread to spin up and create the VisualTarget.
s_event.WaitOne();
return hostVisual;
}
private FrameworkElement CreateMediaElement()
{
// Create a MediaElement, and give it some video content.
MediaElement mediaElement = new MediaElement();
mediaElement.BeginInit();
mediaElement.Source = new Uri("http://download.microsoft.com/download/2/C/4/2C433161-F56C-4BAB-BBC5-B8C6F240AFCC/SL_0410_448x256_300kb_2passCBR.wmv?amp;clcid=0x409");
mediaElement.Width = 200;
mediaElement.Height = 100;
mediaElement.EndInit();
return mediaElement;
}
private void MediaWorkerThread(object arg)
{
// Create the VisualTargetPresentationSource and then signal the
// calling thread, so that it can continue without waiting for us.
HostVisual hostVisual = (HostVisual)arg;
VisualTargetPresentationSource visualTargetPS = new VisualTargetPresentationSource(hostVisual);
s_event.Set();
// Create a MediaElement and use it as the root visual for the
// VisualTarget.
visualTargetPS.RootVisual = CreateMediaElement();
// Run a dispatcher for this worker thread. This is the central
// processing loop for WPF.
System.Windows.Threading.Dispatcher.Run();
}
private static AutoResetEvent s_event = new AutoResetEvent(false);
}
}
因此,OnLoaded创建并设置VisualWrapper的Child属性。我想要做的是允许用户直接在XAML中定义要分配给Child的控件,如:
<local:VisualWrapper Grid.Column="0" Width="200" Height="100" x:Name="Player1"/>
<local:VisualWrapper.ChildSource>
<Button>TEST</Button>
</local:VisualWrapper.ChildSource>
</View:VisualWrapper>
计划是将一个ChildSource DependencyProperty添加到VisualWrapper类中,每当该属性更改时,重新创建它的Child内容。问题是当我尝试从VisualWrapper中访问ChildSource控件时:
public FrameworkElement ChildSource
{
get { return (FrameworkElement)this.GetValue(ChildSourceProperty); }
set { this.SetValue(ChildSourceProperty, value); }
}
我收到一个错误:“调用线程无法访问此对象,因为另一个线程拥有它。”我无法让它工作,我想知道它是否可能。
我尝试在getter中使用Dispatcher:
public FrameworkElement ChildSource
{
get { return (FrameworkElement)Dispatcher.Invoke((Delegate)GetValue(ChildSourceProperty)); }
set { this.SetValue(ChildSourceProperty, value); }
}
但那没用。我的感觉是需要一些Disaptcher.Invoke,但我不确定在哪里。
我想做的是什么?
答案 0 :(得分:1)
没有
WPF创建具有线程关联的对象,然后只能从创建它们的线程中使用这些对象。这意味着如果要在线程之间拆分UI,则必须在将要使用它的线程上创建每个控件。