WPF:用主窗口生成了一个窗口,怎么在新窗口控制主窗口的textblock显示文字?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF:用主窗口生成了一个窗口,怎么在新窗口控制主窗口的textblock显示文字?相关的知识,希望对你有一定的参考价值。

给新窗口定义事件。

这里由于字数限制,两个窗口我都用同一个类了。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock x:Name="label" VerticalAlignment="Top" Text="Hello!" Margin="10,99,10,0" />
        <TextBox x:Name="txtInput" VerticalAlignment="Center" Text="Hello!" HorizontalAlignment="Left" Height="20" Width="456"/>
        <Button Content="点我" HorizontalAlignment="Left" VerticalAlignment="Top" Click="Button_Click"/>
        <Button Content="修改" HorizontalAlignment="Right" VerticalAlignment="Top" Click="Button_Click_1" Margin="0,154,10,0"/>
    </Grid>
</Window>

using System;
using System.Windows;

namespace WpfApplication1

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();
        
        /// <summary>
        /// 处理文本变化时间的委托
        /// </summary>
        public delegate void TextChangedHandler(object sender, TextChangedArgs e);
        /// <summary>
        /// 用来记录变化的文本
        /// </summary>
        public class TextChangedArgs : EventArgs
        
            public string Text  get; set; 
            public TextChangedArgs(string text)
            
                Text = text;
            
        
        /// <summary>
        /// 文本变化事件
        /// </summary>
        public event TextChangedHandler TextChanged;

        private void Button_Click(object sender, RoutedEventArgs e)
        
            MainWindow mw = new MainWindow();

            mw.TextChanged += Mw_TextChanged;
            mw.Show();
        
        /// <summary>
        /// 处理TextChanged事件
        /// </summary>
        private void Mw_TextChanged(object sender, TextChangedArgs e)
        
            this.label.Text = e.Text;
        

        private void Button_Click_1(object sender, RoutedEventArgs e)
        
            if (TextChanged != null)
            
                //引发事件,txtInput.Text 可以改成任意字符串
                TextChanged.Invoke(this, new TextChangedArgs(txtInput.Text));
            
        
    

参考技术A 把主窗口的引用传到新窗口里追问

能写个代码吗?就是自己试了不成功才来问别人的T^T

追答

主窗口:form1=new form1(this)
子窗口:
class form2

public form2(form1 f)

把f用变量保存起来。想用的时候调用

在新线程错误上创建 WPF 新窗口

【中文标题】在新线程错误上创建 WPF 新窗口【英文标题】:WPF new window creation on new thread error 【发布时间】:2015-08-30 22:49:03 【问题描述】:
void itemCommand_Click(Office.CommandBarButton Ctrl, ref bool CancelDefault)

    var thread = new Thread(() =>
    
    if (LoginCheck())
    
        ItemWindow itw = new ItemWindow(); 
        //Dispatcher.CurrentDispatcher.Invoke((System.Action)(() =>
        //
              itw.Show();
              itw.Closed += (sender2, e2) =>  itw.Dispatcher.InvokeShutdown(); ;
        //));

        Dispatcher.Run();
     
     );

    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();


我不断收到错误消息“调用线程无法访问此对象,因为不同的线程拥有它。”在线“itw.show();”当此函数调用两次时。第一次调用它工作正常,在窗口关闭并尝试再次打开后,它失败了。当我注释掉“Invoke”方法时,它也不适用于 Dispatcher。请帮助我找到解决方案。 谢谢。

----------------- 编辑

我创建一个新线程的原因是因为它是一个 Excel 插件。如果我从主线程创建它们,我无法从主线程创建窗口,这是与窗口冲突的 excel。 我不明白的是,为什么新线程中的新实例(ItemWindow)会与旧线程发生冲突。

【问题讨论】:

为什么要创建一个新线程来显示这个窗口?这通常不是一个好主意。其次,我已经尝试过了,效果很好(除了我不知道LoginCheck 做了什么)。异常发生在哪里? 所有与 UI 相关的代码都必须在主线程中运行。您想在这里实现什么目标? 通常,此错误是指您尝试从已串接的表单访问第一个表单上的属性。我们实际上必须看看导致问题的第二种形式发生了什么。 你为什么要创建一个新的调度程序?您是否希望每个窗口都有一个专用的 UI 线程? LoginCheck() 执行的操作会跨入主线程的边界(可能),或者您在 App.xaml 中定义了您在应用程序范围内使用的资源。一旦像这样生成第二个窗口线程,它就会因这个错误而崩溃,因为它试图拉取 App.xaml 中定义的资源,这些资源属于主线程。 【参考方案1】:

我在一个新应用程序中创建了一个简单的测试方法,当我单击主窗体上的(唯一)按钮时调用该方法。该方法如下所示:

private void Button_Click(object sender, RoutedEventArgs e)

    Thread thread = new Thread(() =>
    
        Window1 window = new Window1();
        window.Closed += (s, a) => window.Dispatcher.InvokeShutdown();
        window.Show();
        System.Windows.Threading.Dispatcher.Run();
    );

    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();

Window1 是我制作的一个窗口类,上面只有一个 TextBlock。我可以根据需要多次单击该按钮,它会继续打开新窗口而没有问题(无论我是否先关闭前一个窗口)。

我怀疑问题出现在您没有在某处向我们展示的代码中。您需要非常小心,新线程上的任何内容都不会尝试访问与主线程相关的任何 UI。运行在不同线程上的 Windows 不能相互通信,除非它们通过另一个线程的调度程序。当从创建对象的线程以外的线程访问 DispatcherObject 的任何方法或属性时,将引发您看到的异常。

退一步说,为什么新窗口在自己的线程上很重要?除非新窗口要独占线程,否则它可能会在主线程上运行良好。如果您正在运行一些长时间的阻塞操作,那么可能应该将该操作单独移动到一个线程而不是整个窗口。我不知道你到底在做什么,但这是值得考虑的事情。


编辑:意识到您可能不是在典型的 WPF 应用程序中运行(看起来您可能在 Office 插件中),我更新了我的测试以在它们自己的线程上完全独立地启动窗口。但是,我仍然能够连续启动两个窗口而没有问题。

这是我的新测试。这个方法和测试类Window1是我的应用的全部。

[STAThread]
public static int Main(string[] args)

    ThreadStart threadFunc = () =>
    
        Window1 window = new Window1();
        window.Closed += (s, a) => window.Dispatcher.InvokeShutdown();
        window.Show();
        System.Windows.Threading.Dispatcher.Run();
    ;

    Thread thread = new Thread(threadFunc);
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();

    thread = new Thread(threadFunc);
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();

    return 0;

因此,您尝试做的事情似乎没有任何内在错误,我也没有在您的代码中看到任何明显的问题。我怀疑在显示自定义窗口时某处发生了一些无效的跨线程通信。 (要么是这样,要么你遇到了特定于 Office 插件的问题。)

【讨论】:

我认为这与 excel 插件有关。我不明白的是,为什么新线程中的新实例(ItemWindow)会与旧线程发生冲突。 查看异常的调用栈了吗?也许它会揭示一些关于是什么导致无效调用的线索。此外,您可以关闭“仅我的代码”调试器选项以在 Visual Studio 的“调用堆栈”窗口中查看完整的调用堆栈(包括来自外部程序集的方法)。【参考方案2】:

您正在尝试将事件处理程序连接到 ItemWindow 之后它已经可见。

您需要从以下位置切换订单:

ItemWindow itw = new ItemWindow(); 
itw.Show();
itw.Closed += (sender2, e2) =>  itw.Dispatcher.InvokeShutdown(); ;

ItemWindow itw = new ItemWindow(); 
itw.Closed += (sender2, e2) =>  itw.Dispatcher.InvokeShutdown(); ;
itw.Show();

【讨论】:

【参考方案3】:

一个可能的原因是依赖属性。在线程方面,依赖属性有点挑剔。

即使你不定义自己的 DepProps,你的窗口仍然会有一些,而且没有办法摆脱它们。

DepProps 有一个明显的缺点:它们是线程绑定的,不能从另一个线程访问。哪个线程拥有所有权限由初始化 DepProps 的线程定义,在您的情况下是对new ItemWindow() 的第一次调用。在第一次调用之后,您的线程已设置,您需要该线程来访问您的 DepProps。

第一个窗口没有问题,但第二个显然有不同的线程。我不知道 DepProps 是如何做到这一点的,但您可以尝试捕获和恢复第一个线程的同步上下文。另一种选择是捕获第一个线程的调度程序(不是主线程)

【讨论】:

以上是关于WPF:用主窗口生成了一个窗口,怎么在新窗口控制主窗口的textblock显示文字?的主要内容,如果未能解决你的问题,请参考以下文章

wpf关闭主窗口询问“退出”的问题

初学:我现在用VS2010编写WPF应用程序,一个窗口变化到另一个窗口应该怎么跳转?谢谢

WPF怎样关闭当前窗口

wpf怎么实现主窗口向用户控件传值?

如何关闭 WPF 中隐藏的主窗口?

wpf 怎么在窗口里面显示一个窗口!