Для бэкэнда MySQLdb я изменил внушительный ответ Альбертова (спасибо большое!). Я уверен, что они могут быть объединены, чтобы проверить, было ли comp.positional True, но это немного выходит за рамки этого вопроса.
def compile_query(query):
from sqlalchemy.sql import compiler
from MySQLdb.converters import conversions, escape
dialect = query.session.bind.dialect
statement = query.statement
comp = compiler.SQLCompiler(dialect, statement)
comp.compile()
enc = dialect.encoding
params = []
for k in comp.positiontup:
v = comp.params[k]
if isinstance(v, unicode):
v = v.encode(enc)
params.append( escape(v, conversions) )
return (comp.string.encode(enc) % tuple(params)).decode(enc)
Почему привязка TextBox не работает правильно в первом примере?
Это потому, что TypeDescriptor
из DataRow
не имеет свойства Id
. Рассмотрим следующие правила:
Когда привязка данных к свойству элемента, дескриптор типа элемента должен содержать свойство с таким именем.
При привязке данных к списку дескриптор типа элемента списка должен содержать свойство с таким именем.
Верно ли говорить, что автоматическое (без какого-либо дополнительного вызова для связывания do) распространение из источника в управление происходит только с DataRow?
Нет. Это не из-за типа DataRow
. Это из-за INotifyPropertyChanged
и IBindingList
. Рассмотрим следующие правила:
Когда данные связывают элемент управления с элементом, если элемент реализует INotifyPropertyChanged
, пользовательский интерфейс будет обновляться сразу после обновления элемента.
При привязке данных к элементу управления списком, если элемент реализует INotifyPropertyChanged
и список реализует IBindingList
, пользовательский интерфейс будет обновляться сразу после обновления элемента или списка.
Дополнительная информация
Коротко о том, что я описал выше, вы можете найти в Привязка данных Windows Forms . Я рекомендую прочитать следующие полезные документы:
Так как, может быть, описание этой процедуры в комментариях не очень хорошая идея, вот расширенная версия .
List<T>
в качестве объекта хранения данных (я предпочитаю BindinList
, но здесь IList
будет выполнять эту работу в любом случае) . [тысяча сто двадцать восемь] Определите BindingSource , который будет предоставлять уведомления об изменениях и управление валютой. Это значительно упрощает привязку элементов управления в WinForms.
Установите свойство BindingSource.DataSource для объекта, который предоставляет данные: здесь, BindingList
или [ 115] [одна тысяча сто сорок два].
TextBox.Text
, которое будет связано со свойством источника данных (или, например, столбца таблицы данных), установив [ 1121] DataSource
значение Binding
для BindingSource
и значение DataMember
для свойства (или столбца) источника данных, для которого свойство TextBox является связанным. Здесь свойство Id
класса Inputs
. Binding
, чтобы выделить средства для проверки данных, введенных в TextBox, перед разрешением обновления источника данных. Если введенное значение не соответствует описанию (т. Е. Пользователь вводит буквы вместо цифр), мы можем вызвать, например, метод BindingSource.ResetCurrentItem , чтобы отменить обновление данных DataGridView.DataSource
значение BindingSource
.
Вот что происходит, используя код, показанный здесь:
<час> Примечание :
Я использую лямбду здесь, чтобы подписаться на событие Parse
; Вы можете захотеть использовать отдельный обработчик, если вам нужно подписаться / отписаться на это событие более одного раза.
internal class Inputs
{
public int Id { get; set; }
public string Name { get; set; }
}
internal List<Inputs> InputData = new List<Inputs>();
internal BindingSource bindingSource;
private void button1_Click(object sender, EventArgs e)
{
bindingSource = new BindingSource();
InputData.AddRange(new [] {
new Inputs() { Id = 5476, Name = "Smith" },
new Inputs() { Id = 5477, Name = "Marlin" }
});
bindingSource.DataSource = InputData;
Binding tboxBind = new Binding("Text", bindingSource, "Id", false, DataSourceUpdateMode.OnPropertyChanged);
tboxBind.Parse += (pObj, pEvt) =>
{
if (!int.TryParse(pEvt.Value.ToString(), out int value))
bindingSource.ResetCurrentItem();
};
textBox1.DataBindings.Add(tboxBind);
dataGridView1.DataSource = bindingSource;
}