Как предотвратить автоматическое создание столбцов конструктора Visual Studio в DataGridView?
я генерирую все мои столбцы в подклассе DataGridView
программно. Однако Visual Studio 2008 продолжает читать мой класс конструктора (который заполняет DataTable
С пустым содержимым и привязывает его к DataGridView
) и генерирует код для столбцов InitializeComponent
метод-в настройке процесса AutoGenerateColumns
до false
.
это вызывает ошибки в компиляции времени разработки, которые решаются только вручную, входя в код разработки и удаляя все ссылки на них столбцы автоматически.
как я могу остановить это?
я пробовал:
- сделать контроль "замороженным"
- задание
DataGridView
объектprotected
(предложено в предыдущем посте, который ссылался на этот сайт)
10 ответов
похоже, что вы добавляете элементы управления в конструктор. Возможно, добавьте столбцы немного позже - возможно, что-то вроде переопределения OnParentChanged
; затем вы сможете проверить DesignMode
таким образом, вы добавляете столбцы только во время выполнения (не во время проектирования).
Я видел это поведение раньше для ComboBox с свойством Items, и это действительно расстраивает. Вот как я обошел это с ComboBox. Вы должны иметь возможность применить это к DataGridView.
Я создал" новое " свойство под названием Items и установил его не просматриваемым и явно скрытым от сериализации. Под капотом он просто получает доступ к недвижимости.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new ObjectCollection Items
{
get { return ((ComboBox)this).Items; }
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new object DataSource
{
get { return ((ComboBox)this).DataSource; }
Марк был прав. Дизайнер смотрит на конструктора такого поведения автогенераторный. Вот как я обошел это.
взял код, который создает / связывает DataTable с DataGridView из конструктора и поместил его в метод.
С помощью Load
событие на содержа форме, которая содержит несколько DataGridView
s вызовите BindData()
метод на каждом экземпляре,
List<Control> childControls = Misc.Misc.GetAllChildControls(this);
foreach (Control ctrl in childControls) {
if (ctrl is WorksheetGridView) {
WorksheetGridView wsgv = ctrl as WorksheetGridView;
wsgv.BindData();
}
}
здесь GetAllChildControls
метод в хелпер класс!--7-->
internal static List<Control> GetAllChildControls(Control topControl)
{
List<Control> ctrlStore = new List<Control>();
ctrlStore.Add(topControl);
if (topControl.HasChildren)
{
foreach (Control ctrl in topControl.Controls)
{
ctrlStore.AddRange(GetAllChildControls(ctrl)); }
}
}
return ctrlStore;
}
Извините, если это явное, но я никогда не хочу забывать, как это сделать!
Я столкнулся с проблемой, подобной этой, и размещаю свое решение здесь, так как, когда я написал свой вопрос, это был верхний предложенный вопрос. Каждый раз, когда я компилировал свой код, дизайнер автоматически добавлял каждый из столбцов в источник данных (и в следующий раз, когда я создавал свой код, они появлялись в запущенном приложении), несмотря на то, что автогенеративные столбцы были установлены в false.
В конце концов мне удалось остановить его, дав одному из моих столбцов то же имя, что и автоматически сгенерированный столбец (мои столбцы изначально были созданы вручную до того, как источник данных был доступен).
JaredPar работал для меня:
public partial class RefusjonsOppgjorGrid : DataGridView
{
public RefusjonsOppgjorGrid()
{
InitializeComponent();
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new DataGridViewColumnCollection Columns
{
get{ return base.Columns;}
}
}
Я часто делаю это в моих пользовательских элементах управления, если вы оберните код, который вы не хотите выполнять в конструкторе в проверке DesignMode, он должен устранить ваши проблемы.
if (!DesignMode)
{
// Your code here
}
это старые вопросы сейчас, но это все еще проблема в 2014 году с VS2013.
Я DataGridView
с DataSource
установлен BindingSource
который в свою очередь имел другой BindingSource
как его DataSource
. Чтобы решить мою проблему, мне не нужно было ничего менять, кроме перемещения DataGridView.Назначение источника данных в OnControlCreate
переопределить форму.
@JaredPar это!--5--> получил меня большую часть пути к решению этого, но любые элементы управления, которые содержали мой DataGridView
подкласс добавит столбцы всякий раз, когда что-либо в конструкторе изменится.
Я хотел сохранить столбцы в конструкторе, чтобы их можно было увидеть в визуальном конструкторе, поэтому мне пришлось отключить стандартный DataGridViewDesigner
что мой подкласс унаследовал от своей базы, т. е. Я изменил атрибут Designer для своего класса...
using System.Windows.Forms.Design;
[Designer(typeof(ControlDesigner))]
public class SpecificDataGridView : DataGridView
{
[Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new DataGridViewColumnCollection Columns
{
get { return base.Columns; }
}
...etc...
}
Это значит, что дизайнеры не могут использовать "редактировать элементы" и т. д. В задачах DataGridViewDesigner, и они не могут настроить свойства столбцов, если захотят, но для моих нужд это не было особенно полезно, поэтому это не было потерей.
В любом случае, это исправило проблему, и это все еще означало, что столбцы были видны в дизайнере, который был моей основной целью здесь.
просто подумал, что поделюсь.
поскольку это все еще кажется вопросом для некоторых, включая меня до нескольких дней назад, я думал, что опубликую свое решение, и тот, который я преподаю студентам в своих классах с этого момента:
во-первых, я создаю DataGridView
(DGV) объект и создайте столбцы в представлении конструктора, принимая во внимание Имя объекта для конкретного столбца.
теперь, когда я хочу связать данные из моей базы данных (SQL Server, для этого кода). Я изменяю объекты column и связываю каждый столбец непосредственно к данным из DataTable
.
private void FillAddresses()
{
// erase any old data
if (AddrTable != null)
AddrTable.Clear();
else
AddrTable = new DataTable();
// switch-case for panel types that need an address
switch(PanelType)
{
case "Customer":
case "Customers":
case "Location":
case "Locations":
case "Employee":
case "Employees":
BuildStateColumnChoices();
SqlCommand sqlAddrCmd = new SqlCommand();
sqlAddrCmd.CommandText = "exec SecSchema.sp_GetAddress " + PanelType +
"," + ObjectID.ToString(); // Fill the DataTable with a stored procedure
sqlAddrCmd.Connection = DBConnection;
sqlAddrCmd.CommandType = CommandType.Text;
SqlDataAdapter sqlDA = new SqlDataAdapter(sqlAddrCmd);
try
{
sqlDA.Fill(AddrTable);
dgvAddresses.AutoGenerateColumns = false;
// Actually, you set both the DataSource and DataPropertyName properties to bind the data
dgvAddresses.DataSource = AddrTable;
// Note that the column parameters are using the name of the object from the designer.
// This differs from the column names.
// The DataProperty name is set to the column name returned from the Stored Procedure
dgvAddresses.Columns["colAddrType"].DataPropertyName = "Type";
dgvAddresses.Columns["collAddress"].DataPropertyName = "Address";
dgvAddresses.Columns["colAptNum"].DataPropertyName = "Apt#";
dgvAddresses.Columns["colCity"].DataPropertyName = "city";
dgvAddresses.Columns["colState"].DataPropertyName = "State";
dgvAddresses.Columns["colZIP"].DataPropertyName = "ZIP Code";
}
catch(Exception errUnk)
{
MessageBox.Show("Failed to load address data for panel type " +
PanelType + "..." + errUnk.Message, "Address error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
break;
}
}
для вышеуказанного кода DBConnection является общедоступным свойством для объекта, из которого я взял этот код, в котором хранится SqlConnection
"объект". Кроме того, colAddressType был столбцом ComboBox. Данные из bound DataTable
может совпадать только с информацией, указанной в поле со списком. Аналогично colState является столбцом ComboBox, но значения по умолчанию для этого поля добавляются путем запроса другой таблицы, содержащей все состояния (в США, например).
дело здесь в том, что вы можете связать данные, которые вы хотите включить в DGV, создав столбцы во время разработки, а затем привязать свои данные из DataTable к столбцам напрямую. Это позволяет иметь любой тип столбца, а не только TextColumn по умолчанию, который предоставляется механизмом привязки по умолчанию.
следует отметить, что в этом случае DataTable является результатом хранимой процедуры и такое редактирование в данном случае маловероятно. Я попытался использовать представление, а также сохраненную функцию; первый также не позволял редактировать (по крайней мере, нелегко...Я подозреваю, что мне нужна вставка перед триггером где-то, но это вопрос базы данных), в то время как второй не вернет таблицу на основе какой-то проблемы с динамическим созданием таблицы.
повторно откройте форму в конструкторе, чтобы столбцы были автоматически сгенерированы, затем нажмите на DataGridView, выберите Редактировать столбцы, пройдите через каждый оскорбительный столбец и установите для свойства "Visible" значение False. Повторно сохраните и закройте/повторно откройте форму, чтобы убедиться, что этого больше не происходит. Это было единственное некодирующее решение, которое действительно работало для меня, и я не хотел добавлять код для решения проблемы WinForms designer.