await page.$('a')
возвращает массив с ElementHandles - это объекты со своим собственным API, специфичным для pupeteer, у них нет обычного DOM API для элементов HTML или узлов DOM. Поэтому вам нужно либо получить атрибуты / свойства в контексте браузера через page.evaluate()
, либо использовать довольно сложный API ElementHandles. Это пример с обоими способами:
'use strict';
const puppeteer = require('puppeteer');
(async function main() {
try {
const browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.goto('https://example.org/');
// way 1
const hrefs1 = await page.evaluate(
() => Array.from(
document.querySelectorAll('a[href]'),
a => a.getAttribute('href')
)
);
// way 2
const elementHandles = await page.$('a');
const propertyJsHandles = await Promise.all(
elementHandles.map(handle => handle.getProperty('href'))
);
const hrefs2 = await Promise.all(
propertyJsHandles.map(handle => handle.jsonValue())
);
console.log(hrefs1, hrefs2);
await browser.close();
} catch (err) {
console.error(err);
}
})();
Вы рассмотрели разъединение dataGrid или bindingSource при заполнении таблицы и повторном подключении впоследствии? Это могло бы выглядеть немного ужасным, но это должно быть намного быстрее.
Можно попытаться использовать метод Слияния на DataTable. Я попытаюсь создать простое демонстрационное приложение и отправить его здесь, но идея проста. Когда Вы захотите обновить Сетку, запросите результаты в новый DataTable и затем объедините старую таблицу с новой таблицей. Пока обе таблицы имеют первичные ключи (можно создать их их, я - память, если они не возвращаются из DB), затем, это должно отследить изменения и обновить DataGridView беспрепятственно. Это также имеет преимущество не потери пользовательского места на сетке.
Хорошо, вот образец. Я создаю форму с двумя кнопками и одним dataGridView. При щелчке button1 я заполняю основную таблицу с некоторыми данными и связываю сетку с ним. Затем при втором щелчке я составляю другую таблицу с той же схемой. Добавьте данные к нему (некоторые, которые имеют тот же первичный ключ и некоторых, которые имеют новые). Затем они объединяют их назад с исходной таблицей. Это обновляет сетку как ожидалось.
public partial class Form1 : Form
{
private DataTable mainTable;
public Form1()
{
InitializeComponent();
this.mainTable = this.CreateTestTable();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
this.mainTable.Rows.Add(String.Format("Person{0}", i), i * i);
}
this.dataGridView1.DataSource = this.mainTable;
}
private void button2_Click(object sender, EventArgs e)
{
DataTable newTable = this.CreateTestTable();
for (int i = 1; i <= 15; i++)
{
newTable.Rows.Add(String.Format("Person{0}", i), i + i);
}
this.mainTable.Merge(newTable);
}
private DataTable CreateTestTable()
{
var result = new DataTable();
result.Columns.Add("Name");
result.Columns.Add("Age", typeof(int));
result.PrimaryKey = new DataColumn[] { result.Columns["Name"] };
return result;
}
}
Если Вы используете a BindingSource
для сложной привязки данных важно понять это SuspendBinding
и ResumeBinding
только приостановите и продолжите связывать для текущего объекта. Это позволяет Вам отключить привязку для текущего объекта и изменить набор его свойств без любого из отдельных изменений в свойстве, выставляемом к связанному элементу управления. (Это не объяснено в документации для BindingSource
, где это было бы полезно, о нет: это находится в документации для CurrencyManager
.)
Любые изменения, которые Вы вносите в другие объекты в списке, т.е. всем кроме текущего объекта, повышают ListChanged
событие. При отключении этих событий BindingSource прекращает говорить связанный элемент управления об изменениях в списке, пока Вы не повторно включаете им. Это имеет результат, который Вы видели: Вы добавляете все свои строки к базовому DataTable
, но так как Вы повернулись ListChanged
события прочь, BindingSource
не говорит DataGridView
о них, и таким образом, DataGridView
остается пустым.
Надлежащее решение состоит в том, чтобы звонить ResetBindings
, который вызывает BindingSource
обновить все средства управления, связанные с ним, с помощью текущих значений в его связанном списке.
Какие исключения - Вы добирающийся после вызова ResetBindings
? Поскольку это работает просто великолепно для меня, добавляю ли я, редактирую, удаляю или удаляю строки из базового DataTable
.
Я столкнулся с похожей проблемой. Вот решение, которое еще проще (хотя и менее элегантно).
Я обнаружил, что это:
dataGridView.DataSource = null;
dataTable.BeginLoadData();
foreach(DataRow row in dataTable.Rows){
//modify row
}
dataTable.EndLoadData();
dataGridView.DataSource = dataTable;
...намного быстрее, чем это:
dataTable.BeginLoadData();
foreach(DataRow row in dataTable.Rows){
//modify row
}
dataTable.EndLoadData();
Cheers--DC