C# DataGridView:组合框设置

C# DataGridView:组合框设置,c#,winforms,datatable,datagridview,datagridviewcombobox,C#,Winforms,Datatable,Datagridview,Datagridviewcombobox,我有一个简单的2表设置,“团队”和“球员”。每个玩家都有一个(可为空的)int-TeamID(首选AllowDBNull,但默认值为-1也可以)。 我在两个表中插入/更新/删除记录,这些记录都是可靠的(小测试数据库中的mathich ID)。 设置如下所示: private void initDataSet() { dataSet = new DataSet( "DataBase" ); var dtPlayers = new DataTable( &quo

我有一个简单的2表设置,“团队”和“球员”。每个玩家都有一个(可为空的)int-TeamID(首选AllowDBNull,但默认值为-1也可以)。 我在两个表中插入/更新/删除记录,这些记录都是可靠的(小测试数据库中的mathich ID)。 设置如下所示:

private void initDataSet()
{
    dataSet = new DataSet( "DataBase" );

    var dtPlayers = new DataTable( "Players" );

    dtPlayers.Columns.Add( new DataColumn() {
        ColumnName = "ID" ,
        Caption = "ID" ,
        DataType = typeof( int ) ,
        Unique = true ,
        AutoIncrement = true ,
    } );

    dtPlayers.Columns.Add( new DataColumn() {
        ColumnName = "TeamID" ,
        Caption = "Team" ,
        DataType = typeof( int ) ,
        //AllowDBNull = true ,
        //DefaultValue = DBNull.Value ,
    } );

    dataSet.Tables.Add( dtPlayers );

    var dtTeams = new DataTable( "Teams" );

    dtTeams.Columns.Add( new DataColumn() {
        ColumnName = "ID" ,
        Caption = "ID" ,
        DataType = typeof( int ) ,
        Unique = true ,
        AutoIncrement = true ,
    } );

    dtTeams.Columns.Add( new DataColumn() {
        ColumnName = "FullName" ,
        Caption = "Full Name" ,
        DataType = typeof( string ) ,
    } );

    dataSet.Tables.Add( dtTeams );

    dtPlayers.PrimaryKey = new DataColumn[] { dtPlayers.Columns[ "ID" ] };
    dtTeams.PrimaryKey = new DataColumn[] { dtTeams.Columns[ "ID" ] };

    dataSet.Relations.Add( "Team - Player" , dtTeams.Columns[ "ID" ] , dtPlayers.Columns[ "TeamID" ] );
}
现在我想用一个下拉列表来显示players表中的球队,默认选择为空(意味着没有球队被选中-值为r-1或null,稍后会变成DBNull)。 为此,我为DataGridViewComboBoxColumn设置了DataGridView和一个附加的DataTable作为
.DataSource
。 每次选择/编辑下拉列表时,我都会更新dtTeamIds表以反映更改。 我还设置了适当的
.DisplayMember
.ValueMember
字段

private DataTable dtTeamIds = new DataTable( "TeamIds" ); // datasource for dorpdown-list only

private void updateTeamIds()
{
    var teamsTable = dataSet.Tables[ "Teams" ] as DataTable;
    var items = teamsTable.Rows.Cast<DataRow>()
        .Select( row => new KeyValuePair<string,int>(
            row.Field<string>( "FullName" ) ,
            row.Field<int>( "ID" ) ) )
        .Prepend( new KeyValuePair<string , int>( "---" , -1 ) )
        .ToArray();

    dtTeamIds.Rows.Clear();

    foreach( var item in items )
    {
        var row = dtTeamIds.NewRow();
        row.SetField( dtTeamIds.Columns[ "MyValue" ] , item.Value );
        row.SetField( dtTeamIds.Columns[ "MyText" ] , item.Key );
        dtTeamIds.Rows.Add( row );
    }
}

private void initDataGridViews()
{
    // Players
    {
        var dgv = dataGridViewPlayers;

        dgv.AutoGenerateColumns = false;
        dgv.CausesValidation = false;

        var sourceTable = dataSet.Tables[ "Players" ];
        var dataSrc = sourceTable;

        dgv.Columns.Clear();
        dgv.DataSource = new BindingSource() {
            DataSource = dataSrc ,
        };

        dgv.Columns.Add( new DataGridViewTextBoxColumn() {
            DataPropertyName = "ID" ,
            Visible = false ,
        } );

        // dowpdown-list
        {
            dtTeamIds.Columns.Add( "MyText" );
            dtTeamIds.Columns.Add( "MyValue" );

            updateTeamIds();

            dgv.Columns.Add( new DataGridViewComboBoxColumn() {
                DataPropertyName = "TeamID" ,
                HeaderText = dataSrc.Columns[ "TeamID" ].Caption ,
                ToolTipText = "Press 'CTRL + 0' do delete the team!" ,
                ValueType = typeof( int ) ,
                DisplayMember = "MyText" ,
                ValueMember = "MyValue" ,
                DataSource = new BindingSource( dtTeamIds , null ) ,
            } );
        }

        SetupDataGridViewDefaults( dgv );

        // HACK: see: https://social.msdn.microsoft.com/Forums/en-US/243da031-760d-4e7f-b09f-be4cfa5a6a4b
        dataSrc.ColumnChanging += ( s , e ) => {
            if( e.Column == dataSrc.Columns[ "TeamID" ] )
            {
                var t2 = e.ProposedValue.GetType();

                if( e.ProposedValue == null || ( e.ProposedValue is int val && val == -1 ) )
                {
                    //e.ProposedValue = DBNull.Value; // -1 or NULL
                }                       
            }
        };

        //dgv.CellEnter += ( s , e ) => {
        //  if( e.ColumnIndex == dgv.Columns[ "TeamID" ].Index )
        //  {
        //      updateTeamIds();
        //  }
        //};
        //dgv.CellBeginEdit += ( s , e ) => {
        //  if( e.ColumnIndex == dgv.Columns[ "TeamID" ].Index )
        //  {
        //      updateTeamIds();
        //  }
        //};
        dgv.Click += ( s , e ) => {
            updateTeamIds();
            //if( e.ColumnIndex == dgv.Columns[ "TeamID" ].Index )
            //{
            //  var cell = dgv[ e.ColumnIndex , e.RowIndex ] as DataGridViewComboBoxCell;
            //}
        };

        dgv.CellFormatting += ( s , e ) => {
            if( e.ColumnIndex == dgv.Columns[ "TeamID" ].Index )
            {
                var cell = dgv[ e.ColumnIndex , e.RowIndex ] as DataGridViewComboBoxCell;
                //var _1 = cell.EditedFormattedValue;
                //var _2 = cell.FormattedValue;
                var _3 = cell.Value;    // null
                var _4 = e.Value;       // null
                var _5 = e.DesiredType; // string
            }
        };
    }

    // setup teams-table etc..
}

private void SetupDataGridViewDefaults( DataGridView dgv )
{
    // TODO: figure out how to properly resize columns

    foreach( var colIdx in Enumerable.Range( 0 , dgv.Columns.Count ) )
    {
        var col = dgv.Columns[ colIdx ];

        col.Name = col.DataPropertyName;
        col.MinimumWidth = 50;

        col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;

        if( colIdx == dgv.Columns.Count - 1 )
            col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

        col.Width = col.Width; //This is important, otherwise the following line will nullify your previous command
        col.AutoSizeMode = DataGridViewAutoSizeColumnMode.NotSet;
    }

    dgv.AutoResizeColumns( DataGridViewAutoSizeColumnsMode.AllCells );
    dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    dgv.Columns[ dgv.Columns.Count - 1 ].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

    dgv.AllowUserToResizeColumns = true;
    dgv.AllowUserToOrderColumns = false;
    dgv.AllowUserToResizeRows = true;

    dgv.Enabled = true;
    dgv.Refresh();
}
私有数据表dtTeamIds=新数据表(“TeamIds”);//仅适用于dorpdown列表的数据源
私有void updatetamids()
{
var teamsTable=dataSet.Tables[“Teams”]作为DataTable;
var items=teamsTable.Rows.Cast()
.选择(行=>new KeyValuePair(
行字段(“全名”),
行。字段(“ID”))
.Prepend(新的KeyValuePair(“--”和-1))
.ToArray();
dtTeamIds.Rows.Clear();
foreach(项目中的var项目)
{
var row=dtTeamIds.NewRow();
row.SetField(dtTeamIds.Columns[“MyValue”]、item.Value);
row.SetField(dtTeamIds.Columns[“MyText”],item.Key);
dtTeamIds.Rows.Add(row);
}
}
私有void initDataGridViews()
{
//球员
{
var dgv=DataGridViewPlayer;
dgv.AutoGenerateColumns=false;
dgv.CausesValidation=false;
var sourceTable=dataSet.Tables[“Players”];
var-dataSrc=sourceTable;
dgv.Columns.Clear();
dgv.DataSource=newbindingsource(){
DataSource=dataSrc,
};
添加(新的DataGridViewTextBoxColumn(){
DataPropertyName=“ID”,
可见=假,
} );
//dowpdown列表
{
dtTeamIds.Columns.Add(“MyText”);
dtTeamIds.Columns.Add(“MyValue”);
updatetamids();
添加(新的DataGridViewComboxColumn(){
DataPropertyName=“TeamID”,
HeaderText=dataSrc.Columns[“TeamID”]。标题,
ToolTipText=“按“CTRL+0”确实删除团队!”,
ValueType=typeof(int),
DisplayMember=“MyText”,
ValueMember=“MyValue”,
DataSource=新的BindingSource(DTTeamID,null),
} );
}
SetupDataGridViewDefaults(dgv);
//黑客:见:https://social.msdn.microsoft.com/Forums/en-US/243da031-760d-4e7f-b09f-be4cfa5a6a4b
dataSrc.ColumnChanging+=(s,e)=>{
if(e.Column==dataSrc.Columns[“TeamID”])
{
var t2=e.ProposedValue.GetType();
如果(e.ProposedValue==null | |(e.ProposedValue为int val&&val=-1))
{
//e、 ProposedValue=DBNull.Value;//-1或NULL
}                       
}
};
//dgv.CellEnter+=(s,e)=>{
//如果(e.ColumnIndex==dgv.Columns[“TeamID”].Index)
//  {
//updatetamids();
//  }
//};
//dgv.CellBeginEdit+=(s,e)=>{
//如果(e.ColumnIndex==dgv.Columns[“TeamID”].Index)
//  {
//updatetamids();
//  }
//};
dgv.单击+=(s,e)=>{
updatetamids();
//如果(e.ColumnIndex==dgv.Columns[“TeamID”].Index)
//{
//var cell=dgv[e.ColumnIndex,e.RowIndex]作为DataGridViewComboxCell;
//}
};
dgv.CellFormatting+=(s,e)=>{
如果(e.ColumnIndex==dgv.Columns[“TeamID”].Index)
{
var cell=dgv[e.ColumnIndex,e.RowIndex]作为DataGridViewComboxCell;
//var_1=cell.EditedFormattedValue;
//var_2=cell.FormattedValue;
var _3=cell.Value;//null
var _4=e.Value;//null
var _5=e.DesiredType;//字符串
}
};
}
//设置团队表等。。
}
专用void设置DataGridViewDefaults(DataGridView dgv)
{
//TODO:了解如何正确调整列的大小
foreach(可枚举范围(0,dgv.Columns.Count)中的var colIdx)
{
var col=dgv.Columns[colIdx];
col.Name=col.DataPropertyName;
柱最小宽度=50;
col.AutoSizeMode=DataGridViewAutoSizeColumnMode.AllCells;
if(colIdx==dgv.Columns.Count-1)
col.AutoSizeMode=DataGridViewAutoSizeColumnMode.Fill;
col.Width=col.Width;//这很重要,否则下一行将使上一个命令无效
col.AutoSizeMode=DataGridViewAutoSizeColumnMode.NotSet;
}
dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
dgv.AutoSizeColumnsMode=DataGridViewAutoSizeColumnsMode.None;
dgv.Columns[dgv.Columns.Count-1].AutoSizeMode=DataGridViewAutoSizeColumnMode.Fill;
dgv.AllowUserToResizeColumns=true;
dgv.AllowUserToOrderColumns=false;
dgv.AllowUserToResizeRows=true;
dgv.Enabled=true;
dgv.Refresh();
}
现在,当我启动应用程序时,最初下拉列表是空的(没有选择,不是“---”)。 编辑组合框单元格时,将显示团队和默认的“--”,顶部的选定项将成为“--”项。 在对团队的combobox单元格进行任何更改后,单击任何其他单元格时,我会得到一个FormatException(CBox单元格值无效)

我试图获取有关该值无效的位置或原因的信息,检查CellBegin/EndEdit、Formattin、Changed等事件
private DataTable GetTeamsComboDT() {
  DataTable teams = dataSet.Tables["Teams"].Copy();
  teams.TableName = "TeamsComboDT";
  DataTable players = dataSet.Tables["Players"];
  List<int> teamIDs = new List<int>();
  foreach (DataRow row in teams.Rows) {
    if (row["ID"] != null && !teamIDs.Contains((int)row["ID"])) {
      teamIDs.Add((int)row["ID"]);
    }
  }
  foreach (DataRow row in players.Rows) {
    if (row["TeamID"] != DBNull.Value && !teamIDs.Contains((int)row["TeamID"])) {
      teams.Rows.Add((int)row["TeamID"], "Team " + (int)row["TeamID"] + " ???");
      teamIDs.Add((int)row["TeamID"]);
    }
  }
  DataRow emptyRow = teams.NewRow();
  emptyRow["ID"] = DBNull.Value;
  emptyRow["FullName"] = "---";
  teams.Rows.InsertAt(emptyRow, 0);
  return teams;
}
private DataGridViewComboBoxColumn GetTeamsComboCol() {
  DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
  col.HeaderText = "Team";
  col.Name = "Teams";
  col.DataPropertyName = "TeamID";
  col.ValueMember = "ID";
  col.DisplayMember = "FullName";
  col.DataSource = dataSet.Tables["TeamsComboDT"];
  return col;
}
private void FillTeamsTable() {
  DataTable dt = dataSet.Tables["Teams"];
  for (int i = 0; i < 10; i++) {
    dt.Rows.Add(i + 1, "Team " + (i + 1).ToString());
  }
}


private void FillPlayersTable() {
  DataTable dt = dataSet.Tables["Players"];
  Random rand = new Random();
  int randTeam;
  for (int i = 0; i < 25; i++) {
    randTeam = rand.Next(0, 12);
    switch (randTeam) {
      case 0:
        dt.Rows.Add(i + 1, DBNull.Value);
        break;
      case 11:
        dt.Rows.Add(i + 1, 22);
        break;
      default:
        dt.Rows.Add(i + 1, randTeam);
        break;
    }
  }
}
DataSet dataSet;

public Form2() {
  InitializeComponent();
}

private void Form2_Load(object sender, EventArgs e) {
  dataSet = new DataSet();
  AddTeamsDT_ToDS();
  AddPlayerDT_ToDS();
  FillTeamsTable();
  FillPlayersTable();
  dataSet.Tables.Add(GetTeamsComboDT());
  dataGridView1.Columns.Add(GetTeamsComboCol());
  dataGridView1.DataSource = dataSet.Tables["Players"];
  dataGridView1.Columns["Teams"].DisplayIndex = 1;
}


private void AddPlayerDT_ToDS() {
  DataTable dt = new DataTable("Players");
  dt.Columns.Add("ID", typeof(int));
  dt.Columns.Add("TeamID", typeof(int));
  dataSet.Tables.Add(dt);
}

private void AddTeamsDT_ToDS() {
  DataTable dt = new DataTable("Teams");
  dt.Columns.Add("ID", typeof(int));
  dt.Columns.Add("FullName", typeof(string));
  dataSet.Tables.Add(dt);
}