В настоящее время я столкнулся с этой проблемой: мой проект связывается через интерфейс TR.064 с Fritz! Box (маршрутизатором), чтобы получить информацию о пользователе в моей локальной сети.
Это действие выполняется навсегда в фоновом режиме с использованием BackgroundWorker.
BW вызывает объект класса Communication для получения списка активных хостов. Второй список содержит всех пользователей, которые находятся в определенном списке наблюдения. Пользователи в этом списке наблюдения выделяются.
Затем для каждого пользователя создается ToolStripMenuItem, отображающий имя хоста и его IP-адрес.
Все элементы добавляются во временную переменную класса stati c , чтобы передать его методу bw-RunCompleted.
Теперь этот метод очищает ContextMenuStrip из NotifyIcon и добавляет «стартовое меню», в котором есть стандартные кнопки, такие как выход, настройки, справка и т. д. c.
После этого все элементы временной переменной класса добавляются в ContextMenuStrip.
Но при этом список ToolStripItems временного контекстного меню удаляется после назначения их элементу 'main'-ContextMenuStrip, вызывающий исключение.
Например:
bw получает список из 8 хостов от маршрутизатора. Затем он правильно сохраняет их во временном меню. Во временном меню теперь 8 пунктов.
Когда я l oop через временное меню назначил каждый элемент «главному» меню, этот элемент удаляется из временного списка:
temp | main | items copied
8 | 0 | 0
7 | 1 | 1
-> выдает исключение, потому что список изменился (см. Рисунок)
private static void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
watchBoxCommunicator.askFritzBoxForHosts();
// wait until Communicator finished running
while (watchBoxCommunicator._isRunning) ;
// now create a new menu if needed
// --> only create new menu, if there are new hosts or hosts that went offline
if (watchBoxCommunicator.hosts_on.Count > 0 || watchBoxCommunicator.hosts_off.Count > 0)
{
var tempMenu = new ContextMenuStrip();
//tempMenu.Dock = DockStyle.Bottom;
// first sort the elements in the onlineList
// only sort the watchlist hosts, when there are objects in the list
// the online user list must at least contain one user as the computer running this code is online
List<GetGenericHostEntryResponse> tempListNonWatchlist = watchBoxCommunicator.onlineHosts.OrderBy(hostObject => hostObject.NewHostName).ToList();
List<GetGenericHostEntryResponse> tempListWatchlist = new List<GetGenericHostEntryResponse>();
try
{
tempListWatchlist = watchBoxCommunicator.hostsOnWatchlist.OrderBy(hostObject => hostObject.NewHostName).ToList();
}
catch (ArgumentNullException)
{
// do nothing
tempListWatchlist = new List<GetGenericHostEntryResponse>();
}
finally
{
// back-associate the hosts to the watchBoxCommunicator object to grant access to the sorted lists by other methods
watchBoxCommunicator.onlineHosts = tempListNonWatchlist;
watchBoxCommunicator.hostsOnWatchlist = tempListWatchlist;
}
// add only the hosts that are not on the watchlist
foreach (var host in watchBoxCommunicator.onlineHosts)
{
if (watchBoxCommunicator.hostsOnWatchlist.Contains(host)) continue;
var menuItem = new ToolStripMenuItem();
menuItem.Text = host.NewHostName + " (" + host.NewIPAddress + ")";
menuItem.Enabled = false;
if (host.NewInterfaceType.Equals("Ethernet"))
menuItem.Image = Properties.Resources.network_cable_64px;
else menuItem.Image = Properties.Resources.wi_fi_logo_64px;
tempMenu.Items.Add(menuItem);
}
// add all hosts that are on the watchlist to display them at the top of the menu
foreach (var host in watchBoxCommunicator.hostsOnWatchlist)
{
var menuItem = new ToolStripMenuItem();
menuItem.Text = host.NewHostName + " (" + host.NewIPAddress + ")";
if (host.NewInterfaceType.Equals("Ethernet"))
menuItem.Image = Properties.Resources.network_cable_64px;
else menuItem.Image = Properties.Resources.wi_fi_logo_64px;
menuItem.BackColor = Color.FromArgb(255, 255, 0);
tempMenu.Items.Add(menuItem);
}
// pass the menu to the RunCompleted to update the NotifyIcon's contextmenu
argumentMenu = tempMenu;
}
else
{
argumentMenu = new ContextMenuStrip();
}
}
private static void bw_RunCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
// if the argument's type is a contextmenustrip, update the contextmenu
// otherwise, jump to last line and restart backgroundworker
if (argumentMenu.Items.Count > 0)
{
// interrupt layout updater
wb_menu.SuspendLayout();
wb_menu.Items.Clear();
wb_menu.Items.AddRange(starterMenu.Items);
// add <argumentMenu> item-list to the item-list of <wb_menu>
//wb_menu.Items.AddRange(argumentMenu.Items);
ToolStripItemCollection itemC = argumentMenu.Items;
foreach (var item in itemC)
{
var itemN = item as ToolStripMenuItem;
wb_menu.Items.Add(itemN);
}
// update the <wb_Icon> icon
if (watchBoxCommunicator.hostsOnWatchlist.Count == 0)
{
wb_Icon.Icon = Properties.Resources.WatchBoxFullGreen;
}
else
{
wb_Icon.Icon = Properties.Resources.WatchBoxFullRed;
}
// continue layout updater
wb_menu.ResumeLayout();
}
// start the background-worker again
bw.RunWorkerAsync();
}
Я действительно не знаю, почему список изменяется, когда я добавляю элементы в другой список. Также список не изменяется, не изменяется и не читается другими потоками в любое время при «копировании» элементов.