首页 新闻 会员 周边

WPF 子线程调用主线程资源无法调用问题

0
悬赏园豆:50 [已解决问题] 解决于 2015-12-29 08:25

主窗口代码如下:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Thread thread = new Thread(
                () =>
                {
                    NewWindow win = new NewWindow();
                    win.MainWindow = this;
                    win.Show();
                    System.Windows.Threading.Dispatcher.Run();
                });
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();

            list = new List<BitmapImage>();
            list.Add(new BitmapImage(new Uri("image.png", UriKind.Relative)));
        }

        public List<BitmapImage> list;
    }

子窗口UI及代码:

UI

<Window x:Class="A.NewWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="NewWindow" Height="300" Width="300">
    <Grid>
        <Image x:Name="image" HorizontalAlignment="Left" Height="128" Margin="85,27,0,0" VerticalAlignment="Top" Width="128"/>
        <Button Content="Button" HorizontalAlignment="Left" Height="40" Margin="96,191,0,0" VerticalAlignment="Top" Width="117" Click="Button_Click"/>
    </Grid>
</Window>

后台

public partial class NewWindow : Window
    {
        public NewWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Dispatcher.Invoke(
                new Action(
                    () =>
                    {
                        image.Source = MainWindow.list[0];
                    }));
        }

        public MainWindow MainWindow { get; set; }
    }

点击子窗口Button按钮后报错:

image.Source = MainWindow.list[0];   调用线程无法访问此对象,因为另一个线程拥有该对象。

求高手解答,怎么才能在点击按钮后将图片显示在子窗口中

SystemUser的主页 SystemUser | 初学一级 | 园豆:157
提问于:2015-12-28 16:33
< >
分享
最佳答案
0

private void button1_Click(object sender, RoutedEventArgs e)
{
MainWindow.Dispatcher.Invoke((Action)(() => {
MainWindow.ImageList[0].Freeze();
}));
image.Source = new ImageBrush( MainWindow.ImageList[0]);
}

收获园豆:50
德年 | 小虾三级 |园豆:810 | 2015-12-28 18:04

BitmapImage 调用Freeze()后就可以跨线程使用了。

另外设置Image.Source也要在Image所在的线程上,楼主提供的代码image所在的线程的Dispatcher不等于

Application.Current.Dispatcher。

应该直接在button事件中设置image.Source,不能通过Application.Current.Dispatcher。

德年 | 园豆:810 (小虾三级) | 2015-12-28 18:09

@德年: 谢谢帮忙解决问题。

能帮忙顺便解释下原理吗?

什么样的资源可以在跨线程中使用?

为什么值类型的在使用的时候没有报跨线程异常?是因为值类型引用的是原始的副本的原因吗?

还是说对于那些在内存中不可变的,例如字符串类型的对象,在跨线程操作时不用担心其变化?

还请帮忙解答。

SystemUser | 园豆:157 (初学一级) | 2015-12-29 08:25

@SystemUser: 

https://msdn.microsoft.com/zh-cn/library/system.windows.threading.dispatcher.aspx

里面的备注有讲到Dispatcher与Freezable对象,能解答你的问题。

德年 | 园豆:810 (小虾三级) | 2015-12-29 09:25

@德年: 非常感谢!又学到了新的东西了

SystemUser | 园豆:157 (初学一级) | 2015-12-29 10:10
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册