[.net] OpenFileDialog in dataGridView?

Started by
6 comments, last by TheTroll 16 years, 9 months ago
The goal I'm trying to achieve is that one column in a dataGridView (bound) works using an OpenFileDialog. To clarify, I want a '...'-button in the cell, which if clicked shows an OpenFileDialog, which in turn sets the value of the cell (to OpenFileDialog.FileName). In a propertyGrid I can easily do this by placing
[Editor( typeof( System.Windows.Forms.Design.FileNameEditor ), typeof( System.Drawing.Design.UITypeEditor ) )]
above the property However, it doesn't seem to work for the dataGridView. Is there a way to achieve a similar effect in the dataGridView? Also, I will probably use it for a textbox control as well. Thanks in advance for the help!
Advertisement
What you are looking for is DataGridViewButtonColumn. This allows you to add buttons to any DataGridView Column.

If you have any questions about using it, let me know.
theTroll
Thanks, but a DataGridViewButtonColumn was not what I needed. Turns out what I needed was a user control and a matching class derived from DataGridViewCell. I got it to work though :)
Oops, still got a problem. Creating a column with cells containing my user control works fine, by setting dataGridView.Columns["File"].CellTemplate = new FileControlCell();

However, at some point I want to retrieve the FileControl (which is my user control), because it holds a value (previousValue) I'm interested in. I tried like this:

FileControlCell fileControlCell = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] as FileControlCell;
e.Value = fileControlCell.FileControl.OldValue;

e = the event args, so e.RowIndex and e.ColumnIndex point to the active cell. The code compiles fine, but fileControlCell.FileControl.OldValue (in fact all members of FileControl) are at the state the constructor gave them. OldValue is supposed to have a value (I traced it in the debugger) but it doesn't. So somehow I don't get the right FileControl (I think).

Any suggestions on how to retrieve the data I need?
Anyone? I still can't figure it out. I found some suggestions on overriding the clone() function of the custom DataGridViewCell, but it doesn't get me anywhere. I'll post my current code just in case it's needed (I'm working on it so it might have some bad parts atm)

[source lang=c#]	public class FileControlCell : DataGridViewTextBoxCell	{		static FileControl fileControl = null;		public FileControlCell()		{			fileControl = new FileControl();		}		public override Type EditType		{			get { return typeof( FileControl ); }		}		public FileControl FileControl		{			get { return fileControl; }			set { fileControl = value; }		}		protected override Size GetPreferredSize( Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, Size constraintSize )		{			try			{				if ( this.IsInEditMode )					return fileControl.Size;				else					return base.GetPreferredSize( graphics, cellStyle, rowIndex, constraintSize );			}			catch			{				return base.GetPreferredSize( graphics, cellStyle, rowIndex, constraintSize );			}		}				public override object Clone()		{			FileControlCell cell = base.Clone() as FileControlCell;			if (cell != null)				cell.FileControl = this.FileControl;			return cell;		}	}


[source lang=C#]	public partial class FileControl : UserControl, IDataGridViewEditingControl	{		DataGridView	dataGridView	= null;		int				rowIndex		= 0;		bool			valueChanged	= false;		string			oldValue		= null;		public FileControl()		{			InitializeComponent();			this.txtFilePath.LostFocus += new EventHandler( txtFilePath_LostFocus );		}		void txtFilePath_LostFocus( object sender, EventArgs e )		{			NotifyChange();		}		private void btnBrowse_Click(object sender, EventArgs e)		{			valueChanged = false;			if ( sfdFile.ShowDialog() == DialogResult.OK )				this.txtFilePath.Text = sfdFile.FileName;			NotifyChange();		}		private void NotifyChange()		{			if ( this.txtFilePath.Text != oldValue )			{				valueChanged = true;				dataGridView.NotifyCurrentCellDirty( true );			}		}		public string OldValue		{			get { return oldValue; }			set { oldValue = value; }		}		public void ApplyCellStyleToEditingControl( DataGridViewCellStyle dataGridViewCellStyle )		{		}		public Cursor EditingControlCursor		{			get  { return Cursors.IBeam; }		}		public Cursor EditingPanelCursor		{			get { return Cursors.IBeam; }		}		public DataGridView EditingControlDataGridView		{			get { return dataGridView; }			set { dataGridView = value; }		}		public object EditingControlFormattedValue		{			get { return this.txtFilePath.Text; }			set { this.txtFilePath.Text = value.ToString(); }		}		public int EditingControlRowIndex		{			get { return rowIndex; }			set { rowIndex = value; }		}		public bool EditingControlValueChanged		{			get { return valueChanged; }			set { valueChanged = value;	}		}		public bool EditingControlWantsInputKey( Keys keyData, bool dataGridViewWantsInputKey )		{			switch ( keyData )			{				case Keys.Tab:					return true;				case Keys.Home:				case Keys.End:				case Keys.Left:					if (this.txtFilePath.SelectionLength == this.txtFilePath.Text.Length)						return false;					else						return true;				case Keys.Right:					return true;				case Keys.Delete:					this.txtFilePath.Text = "";					return true;				case Keys.Enter:					NotifyChange();					return false;				default:					return false;			}		}		public object GetEditingControlFormattedValue( DataGridViewDataErrorContexts context )		{			return this.txtFilePath.Text;		}		public void PrepareEditingControlForEdit( bool selectAll )		{			if (this.dataGridView.CurrentCell.Value == null)				this.txtFilePath.Text = "";			else				this.txtFilePath.Text = this.dataGridView.CurrentCell.Value.ToString();			if (selectAll)				this.txtFilePath.SelectAll();			oldValue = this.txtFilePath.Text;		}		public bool RepositionEditingControlOnValueChange		{			get { return false; }		}	}
This should get you on your way, well unless of course you tell me this is not what you need again.

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)        {            string filepath = "";            if (e.ColumnIndex == 3)  /// This is the column that contains your DataGridViewButtonColumn..            {                OpenFileDialog fd = new OpenFileDialog();                if (fd.ShowDialog() == DialogResult.OK)                {                    filepath = fd.FileName;                }                MessageBox.Show(filepath);            }        }


Hope it helps..
theTroll
hmmm that might actually work as well, it would make the custom DataGridViewCell unnecessary. Thanks a whole lot for your help, rating++ of course ;)
By setting the column you want the ... to DataGridViewButtonColumn, it automatically makes that column buttons for you. Then you just set the Column text to "...". I would suggest locking the column to a given size that looks right for the "...", so that if they resize it doesn't resize the buttons.

theTroll

This topic is closed to new replies.

Advertisement