多线程WPF程序界面运行一段时间后卡死,后台代码仍在继续运行

7 篇文章 1 订阅
6 篇文章 0 订阅

1.场景

    使用以太网接收单片机发送的PHY电流的数据包,并在基于WPF实现的C#应用程序上进行分析、显示。上位机采用LiveCharts第三方控件用以显示数据(问题所在),电流采样频率为2ms,每采集20条电流发送一包数据。

2.代码实现

    显示:通过向动态库的事件指针上添加回调函数,并在回调函数内将接收到的数据包存储至Queue,并在后台线程中循环取出队列中已有的数据包,并将其中的数据(电流、时间戳等)添加至已绑定LiveCharts对应的折线图序列,;

    数据保存:队列中的数据包在添加至折线图时,也会存储至DataTable容器中,当容器中对象个数大于某个设定值后,将会开启新线程将表中数据写入.csv文件中

    分析:若包中数据满足某一条件(比如电流大于、小于某个值,时间戳大于某个值等等),调用正在等待的AutoResetEvent对象的Set()函数,使其所在线程继续执行(以满足其他测试需求),完成线程间的同步。

3.问题定位

    这个设定值实际上会在两个地方使用。一是在数据保存前进行判断,二则作为LiveCharts绑定的数据源的一系列点个数的上限,产生导致界面卡死的原因在于,在数据保存的新线程中,移除了数据源溢出的点,错误部分的代码(下面代码在控件创建线程异步执行的Action中运行)如下:

this.Dispatcher.BeginInvoke((Action)(() =>
{
    ...//数据分析用的无关代码
    Thread t = new Thread(new ThreadStart(delegate
    {
        //文件保存
        SaveCSV(data_table, csv_path);
#region  操作数据源代码
        //操作已绑定至LiveCharts控件的数据
        while (Labels.Count > MaxPointsCount)
        {
            //移除X轴标签、Y轴两条折线数据源中起始的点
            Labels.RemoveAt(0);
            SeriesCollection[0]?.Values.RemoveAt(0);
            SeriesCollection[1]?.Values.RemoveAt(0);
            Thread.Sleep(1);
        }
#endregion
    }));
    t.Start();
    ...//无关代码
}));

    调试过程中,每次执行到这一步就会导致界面卡死(实际后台仍在接收并处理数据),对于多线程的理解不够,在将#region...#endregion中的内容从新建线程t的委托中移除并放至线程t外进行运行,问题解决。

    最终认为,此问题和“不能在非控件创建线程中操作控件”是同一个道理,应该遵循WPF规则,在控件对象创建线程中对数据源进行操作。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
好的,以下是WPF动态切换中英文界面代码: 首先,在App.xaml.cs文件中添加一个静态属性,用于存储当前的语言选项。 ```csharp public static string Language { get; set; } = "en-US"; ``` 接着,在App.xaml文件中添加资源字典,并设置其Source属性为当前语言选项对应的资源文件。 ```xaml <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Resources\en-US.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> ``` 然后,在主窗口中添加一个语言切换的ComboBox控件,并为其SelectedValue属性绑定当前语言选项。 ```xaml <ComboBox x:Name="LanguageComboBox" SelectedValue="{Binding Source={x:Static Application.Current}, Path=Language}"> <ComboBoxItem Content="English" Tag="en-US" /> <ComboBoxItem Content="中文" Tag="zh-CN" /> </ComboBox> ``` 接下来,在主窗口的代码中,为语言切换的ComboBox控件的SelectionChanged事件添加处理方法,用于动态切换界面语言。 ```csharp private void LanguageComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var selectedItem = (ComboBoxItem)LanguageComboBox.SelectedItem; var language = (string)selectedItem.Tag; App.Language = language; // 切换资源文件 var dictionary = new ResourceDictionary(); dictionary.Source = new Uri($@"Resources\{language}.xaml", UriKind.RelativeOrAbsolute); Application.Current.Resources.MergedDictionaries.Clear(); Application.Current.Resources.MergedDictionaries.Add(dictionary); } ``` 最后,在资源文件夹中添加两个资源文件,分别对应英文和中文界面。例如,en-US.xaml文件的内容如下: ```xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <SolidColorBrush x:Key="BackgroundColor" Color="#FFFFFF" /> <SolidColorBrush x:Key="ForegroundColor" Color="#000000" /> </ResourceDictionary> ``` zh-CN.xaml文件的内容如下: ```xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <SolidColorBrush x:Key="BackgroundColor" Color="#000000" /> <SolidColorBrush x:Key="ForegroundColor" Color="#FFFFFF" /> </ResourceDictionary> ``` 这样就实现了WPF动态切换中英文界面的功能。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值