【发布时间】:2018-09-17 08:06:10
【问题描述】:
所以我正在开发一个简单的 WPF 应用程序,它应该从我们 LAN 上的“专用页面”读取信息并更有效地输出它们。所以现在我正在尝试在选择要从中获取数据的 ip 后自动更新标签内容。计划基本上是每分钟左右刷新一次页面以更新输出。 问题是我尝试了很多关于多线程的解决方案,但仍然得到相同的错误:InvalidOperationException:调用线程无法访问此对象,因为不同的线程拥有它。 基本上我从中了解到的是 mainWindows 线程拥有标签的内容,因此在从所述文件/字符串读取后我无法更新它们。
这是我的窗口 xaml:
<Window x:Class="PartCountBello.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:PartCountBello"
mc:Ignorable="d"
Title="Controllo Macchine" Height="337.42" Width="366.586"
ResizeMode="CanMinimize">
<Grid Margin="0,10,2,12">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="0*"/>
</Grid.ColumnDefinitions>
<ComboBox x:Name="cmbNomiMacchine" HorizontalAlignment="Left"
Margin="44,74,0,0" VerticalAlignment="Top" Width="129" Height="22"
SelectionChanged="cmbNomiMacchine_SelectionChanged"/>
<Label x:Name="lblNomeDato" Content="PartCount :"
HorizontalAlignment="Left" Margin="44,162,0,0" VerticalAlignment="Top"
Height="26" Width="129"/>
<Label x:Name="lblPartCount" Content="" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="178,162,0,0" Height="26" Width="144"
RenderTransformOrigin="0.071,0.731"/>
<Label x:Name="lblSelectInfos" Content="Selezionare macchina"
HorizontalAlignment="Left" Margin="44,43,0,0" VerticalAlignment="Top"
Width="129" Height="26"/>
<Label x:Name="lblLavoro" Content="Mansione : "
HorizontalAlignment="Left" Margin="44,210,0,0" VerticalAlignment="Top"
Width="129"/>
<Label x:Name="lblMansione" Content="" HorizontalAlignment="Left"
Margin="178,210,0,0" VerticalAlignment="Top" Width="144"/>
<Button x:Name="btnRefresh" Content="Aggiorna"
HorizontalAlignment="Left" Margin="247,74,0,0" VerticalAlignment="Top"
Width="75" Height="22" Click="btnRefresh_Click"/>
<Label x:Name="lblMoreInfos" Content="" HorizontalAlignment="Left"
Margin="10,241,0,0" VerticalAlignment="Top" Width="339" Height="35"/>
</Grid>
</Window>
这是我的 mainWindows 代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
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.Navigation;
using System.Windows.Shapes;
namespace PartCountBello
{
/// <summary>
/// Logica di interazione per MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
List<string> datas = new List<string> { }; //list that contains machines names and relatives ips. each ip is in the previous index...
//respect to the machine.
public MainWindow()
{
InitializeComponent();
try
{
ReadFile rf = new ReadFile(); //creates the file reader we 're using to...
datas = rf.getListFromFile("MyIPsFile"); //get all our datas from our file.. Not posting the real file name here cuz you never know. still contains only the ips to connect to.
for(int i = 2;i<=datas.Count-1;i+=3)
{
cmbNomiMacchine.Items.Add(datas[i]);
}
}
catch (Exception ex)
{
lblMoreInfos.Content = ex.Message;
}
finally
{
}
}
/// <summary>
/// when the selection is changed to an item it will update the labels contents through a method in the class activityChecker.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cmbNomiMacchine_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
updateLabelsContent();
}
/// <summary>
/// gets the index the item selected in the combobox has in the file to pass it to the fileread and get the ip.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
private int getSelectedItemIndex(int index)
{
int FIRST_REAL_INDEX = 2;
int realIndex;
if (index == 0)
return 0;
else
return realIndex=FIRST_REAL_INDEX+index*2;
}
/// <summary>
/// checks if the machine we are trying to connect to is on, if so updates the dedicated lables' content, else prints a simple message down below.
/// </summary>
private void updateLabelsContent()
{
string toShow;//the auxiliary string we are going to use to output on labels.
ActivityChecker ac = new ActivityChecker();
lblMoreInfos.Content = "";
if (getSelectedItemIndex(cmbNomiMacchine.SelectedIndex) != 0)
{
if (PingHost(datas[getSelectedItemIndex(cmbNomiMacchine.SelectedIndex) - 1]))
{
toShow = ac.getPartCount(datas[getSelectedItemIndex(cmbNomiMacchine.SelectedIndex)]);
lblPartCount.Content = toShow;
toShow = ac.getJob(datas[getSelectedItemIndex(cmbNomiMacchine.SelectedIndex)]);
lblMansione.Content = toShow;
}
else
{
lblMoreInfos.Content = "La macchina è al momento spenta.";
}
}
else
{
lblMansione.Content = "";
lblPartCount.Content = "";
}
}
/// <summary>
/// updates the content of the machine dedicated labels.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
updateLabelsContent();
}
/// <summary>
/// allows to verify if the machine we are trying to connect to is on before we actually try to, avoids some freezes.
/// </summary>
/// <param name="nameOrAddress"></param>
/// <returns></returns>
public static bool PingHost(string nameOrAddress)
{
bool pingable = false;
Ping pinger = new Ping();
try
{
PingReply reply = pinger.Send(nameOrAddress);
pingable = reply.Status == IPStatus.Success;
}
catch (PingException)
{
// Discard PingExceptions and return false;
}
return pingable;
}
}
}
【问题讨论】:
-
您能否使用本地磁盘上的文件副本进行测试.. 看看是否正常。这个测试可以消除存储在局域网上的文件的权限或权限问题吗?
-
最懒惰的方式:查看 SynchronizationContext
-
@Frenchy 是的,问题不在于读取文件的问题,而只是不愿意在 2 个线程内共享的标签。文件和阅读部分工作正常。
-
@AlexandruClonțea 我应该如何进入 sychronizationContext?我是多线程编程的新手,所以更详细的东西真的会有所帮助。
标签: c# wpf multithreading xaml