我在Xaml文件中有一个图像控件,如下所示:
<Viewbox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Center">
<Image Name="Content"/>
</Viewbox>
我想每隔10秒用不同的图像更新此图像。 我创建了一个system.threading.Timer实例,使用回调初始化它,将UI控件作为状态对象传递,并将间隔设置为10秒,如下所示:
contentTimer = new Timer(OnContentTimerElapsed, Content , 0 , (long) CONTENT_DISPLAY_TIME);
回调如下:
private void OnContentTimerElapsed( object sender )
{
Image content = (Image)sender;
//update the next content to be displayed
nCurrentImage = (nCurrentImage % NUM_IMAGES) + 1;
//get the url of the image file, and create bitmap from the jpeg
var path = System.IO.Path.Combine(Environment.CurrentDirectory, "../../DisplayContent/Image_" + nCurrentImage.ToString() + ".jpg");
Uri ContentURI = new Uri(path);
var bitmap = new BitmapImage(ContentURI);
//update the image control, by launching this code in the UI thread
content.Dispatcher.BeginInvoke(new Action(() => { content.Source = bitmap; }));
}
我仍然遇到以下异常:
An unhandled exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll
Additional information: The calling thread cannot access this object because a different thread owns it.
我能够通过更新numCurrentImage变量获得解决方案,然后在UI线程上运行的回调中更新MainWindow类中的Content.Source,如下所示(请注意,我在获取帧时)来自kinect的30fps):
int nCurrentImage;
Public MainWindow()
{
InitializeComponent();
nCurrentImage = 1;
System.Timers.Timer contentTimer = new System.Timers.Timer(OnContentTimerElapsed, CONTENT_DISPLAY_TIME);
contentTimer.Elapsed += OnContentTimerElapsed;
...
//Some kinect related initializations
...
kinect.multiSourceReader.MultiSourceFrameArrived += OnMultiSourceFrameArrived;
}
private void OnContentTimerElapsed( object sender )
{
//update the next content to be displayed
nCurrentImage = (nCurrentImage % NUM_IMAGES) + 1;
}
private void OnMultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
{
UpdateContent(nCurrentImage);
}
private void UpdateContent(int numImage)
{
var path = System.IO.Path.Combine(Environment.CurrentDirectory, "../../DisplayContent/Image_" + numImage.ToString() + ".jpg");
Uri ContentURI = new Uri(path);
var bitmap = new BitmapImage(ContentURI);
Content.Source = bitmap;
}
即使这样有效,但是以这种方式更新它并没有很好的编程意义,因为一半的工作是由一个线程完成的,其余的是由UI线程完成的。
任何想法我做错了什么?
答案 0 :(得分:1)
即使这样可行,但是这样做更难以编程,因为一半的工作是由一个线程完成的,其余部分是由UI线程完成的。
实际上这完全你想要做什么。您希望在非UI线程中执行非UI工作,并在UI线程中执行UI工作。
尽管如此,虽然这基本上是你想做的事情,但你不需要自己这么明确地完成所有这些。您可以简单地使用DispatcherTimer
,它将在UI线程中触发回调,而不是线程池线程。它或多或少地做了很多你手动做的事情。
答案 1 :(得分:-1)
更新XAML图像元素,我喜欢用X命名它们,以提醒我它是一个XAML元素。
<Image Name="XContent"/>
当计时器触发时,
...
bitmap.Freeze();
XContent.Dispatcher.Invoke(()=>{
XContent.Source = bitmap;
}