Итак, я работаю над простым приложением WPF, которое должно считывать информацию со «выделенной страницы» в нашей локальной сети и выводить ее более эффективно. Поэтому сейчас я пытаюсь автоматически обновлять содержимое меток после того, как выбран 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>
и вот мой основной код Windows:
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;
}
}
}