ListView Columns/GridlinesOffset/Alignment error [duplicate] - c#

I am trying to write a Windows Forms MusicPlayer application in C#.
The application should show a list and have some play / stop buttons.
I just started half an hour ago, but my design is almost finished. Now I got 3 things to fix. A bug and 2 good looking things:
on the picture you can see the bug I've found. You might say that's nothing, but its a eye catcher. How can I fix this?
how can I align center the headline of a column, without centering the content?
how can I make the last column filling out the rest of the listView?

You can set the TextAlign of all but the 1st Column's Header; it is always left aligned. To change that you need to owner draw it.
There is no automatic filling option so you need to write a setColumnwidth function, that loops over all but the last columns and sums their Widths; then it subtract the sum from the ListView's Clientsize.Width and set the last column's Width.
The display bug in the gridlines is new to me; so far I don't know how to fix it; maybe owner-drawing will help there as well..?
Update:
Here is some code:
void setLastColumnTofill(ListView lv)
{
int sum = 0;
int count = lv.Columns.Count;
for (int i = 0; i < count - 1; i++) sum += lv.Columns[i].Width;
lv.Columns[count - 1].Width = lv.ClientSize.Width - sum;
}
After setting OwnerDraw = true you could code the three (all are needed!) Draw event :
private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
e.Graphics.FillRectangle(SystemBrushes.Menu, e.Bounds);
e.Graphics.DrawRectangle(SystemPens.GradientInactiveCaption,
new Rectangle(e.Bounds.X , 0, e.Bounds.Width , e.Bounds.Height) );
string text = listView1.Columns[e.ColumnIndex].Text;
TextFormatFlags cFlag = TextFormatFlags.HorizontalCenter
| TextFormatFlags.VerticalCenter;
TextRenderer.DrawText(e.Graphics, text, listView1.Font, e.Bounds, Color.Black, cFlag);
}
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
e.DrawDefault = true;
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
e.DrawDefault = true;
}
You may want to play a little with the colors or the widths..
If you have an ImageList containing images for displaying the sort order (or other things) you can add this to draw them as well:
ColumnHeader colH = listView1.Columns[e.ColumnIndex];
int ii = colH.ImageIndex;
if (ii >= 0 && ii < imageList1.Images.Count)
e.Graphics.DrawImage(imageList1.Images[ii],
e.Bounds.Width + e.Bounds.X - imageList1.ImageSize.Width, 0);

After setting OwnerDraw to true you can do other stuff like this:
Draw ListView
int sortIndex = 0;
private void listView1_DrawColumnHeader(object sender,
DrawListViewColumnHeaderEventArgs e)
{
var state = e.State == ListViewItemStates.Selected ?
VisualStyleElement.Header.Item.Hot : VisualStyleElement.Header.Item.Normal;
var sortOrder = listView1.Sorting == SortOrder.Ascending ?
VisualStyleElement.Header.SortArrow.SortedUp :
VisualStyleElement.Header.SortArrow.SortedDown;
var itemRenderer = new VisualStyleRenderer(state);
var sortRenderer = new VisualStyleRenderer(sortOrder);
var r = e.Bounds;
r.X += 1;
itemRenderer.DrawBackground(e.Graphics, r);
r.Inflate(-2, 0);
var flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter |
TextFormatFlags.SingleLine;
itemRenderer.DrawText(e.Graphics, r, e.Header.Text, false, flags);
var d = SystemInformation.VerticalScrollBarWidth;
if (e.ColumnIndex == sortIndex) //Sorted Column
sortRenderer.DrawBackground(e.Graphics,
new Rectangle(r.Right - d, r.Top, d, r.Height));
}
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
e.DrawDefault = true; /*Use default rendering*/
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
e.DrawDefault = true; /*Use default rendering*/
}
Fill ListView using Last Column
private void ListViewSample_Load(object sender, EventArgs e)
{
var otherItemWisth= this.listView1.Columns.Cast<ColumnHeader>()
.Where(x => x.Index < this.listView1.Columns.Count - 1)
.Sum(x => x.Width);
this.listView1.Columns[this.listView1.Columns.Count - 1].Width =
this.listView1.ClientSize.Width - otherItemWisth;
}
Result

Related

How to resize/stretch a text box based on another text box content?

I would like to resize my text box based on another text box content.
This is what I've tried to do.
private void button1_Click(object sender, EventArgs e)
{
receive.AutoSize = true;
receive.Text = send.Text;
}
I want the text box to auto stretch or to resize on X and Y based on another text box content.
Ok, So I found something like this.
private void button1_Click(object sender, EventArgs e)
{
receive.Text = send.Text;
Size sz = new Size(receive.ClientSize.Width, int.MaxValue);
TextFormatFlags flags = TextFormatFlags.WordBreak;
int padding = 3;
int borders = receive.Height - receive.ClientSize.Height;
sz = TextRenderer.MeasureText(receive.Text, receive.Font, sz, flags);
int h = sz.Height + borders + padding;
if (receive.Top + h > this.ClientSize.Height - 10)
{
h = this.ClientSize.Height - 10 - receive.Top;
}
receive.Height = h;
}
But I need to set Maximum Height and Width and minimum. How should I do it?
private void sender_TextChanged/*or button1_Click*/(object sender, EventArgs e)
{
Graphics graph = CreateGraphics();
SizeF measuredStringSize = graph.MeasureString(tb_sender.Text, tb_sender.Font);
tb_receiver.Width = (int)measuredStringSize.Width;
tb_receiver.Text = tb_sender.Text;
}

How to change datagridview column divider color c# winforms

First i tried changing dataGridView1.BackgroundColor, dataGridView1.GridColor but didn't worked.. then i tried dataGridView1.EnableHeadersVisualStyles = false dataGridView1.ColumnHeadersDefaultCellStyle.BackColor = Color.White but nothing worked for me..
You need to handle CellPainting event and fill the background with desired color, for example the same color as GridColor, then perform the rest of painting by limiting the paint area to a rectangle excluding divider:
private void DataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex == -1)
{
var dgv = (DataGridView)sender;
var r = e.CellBounds;
var w = 0;
if (e.ColumnIndex > -1)
{
w = dgv.Columns[e.ColumnIndex].DividerWidth;
r.Width = r.Width - w;
}
e.Graphics.SetClip(r);
e.Paint(r, DataGridViewPaintParts.All);
e.Graphics.SetClip(e.CellBounds);
if (w > 0)
{
r = new Rectangle(r.Right - 1, r.Top, w + 1, r.Height);
using (var brush = new SolidBrush(dgv.GridColor))
e.Graphics.FillRectangle(brush, r);
}
e.Handled = true;
}
}
For example, if you set DividerWidth for the columns to 10 and set GridColor to Color.Red you can get the following result using above code:

ListView - Align vertical grid lines with Headers dividers - Make last Column fill the space

I am trying to write a Windows Forms MusicPlayer application in C#.
The application should show a list and have some play / stop buttons.
I just started half an hour ago, but my design is almost finished. Now I got 3 things to fix. A bug and 2 good looking things:
on the picture you can see the bug I've found. You might say that's nothing, but its a eye catcher. How can I fix this?
how can I align center the headline of a column, without centering the content?
how can I make the last column filling out the rest of the listView?
You can set the TextAlign of all but the 1st Column's Header; it is always left aligned. To change that you need to owner draw it.
There is no automatic filling option so you need to write a setColumnwidth function, that loops over all but the last columns and sums their Widths; then it subtract the sum from the ListView's Clientsize.Width and set the last column's Width.
The display bug in the gridlines is new to me; so far I don't know how to fix it; maybe owner-drawing will help there as well..?
Update:
Here is some code:
void setLastColumnTofill(ListView lv)
{
int sum = 0;
int count = lv.Columns.Count;
for (int i = 0; i < count - 1; i++) sum += lv.Columns[i].Width;
lv.Columns[count - 1].Width = lv.ClientSize.Width - sum;
}
After setting OwnerDraw = true you could code the three (all are needed!) Draw event :
private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
e.Graphics.FillRectangle(SystemBrushes.Menu, e.Bounds);
e.Graphics.DrawRectangle(SystemPens.GradientInactiveCaption,
new Rectangle(e.Bounds.X , 0, e.Bounds.Width , e.Bounds.Height) );
string text = listView1.Columns[e.ColumnIndex].Text;
TextFormatFlags cFlag = TextFormatFlags.HorizontalCenter
| TextFormatFlags.VerticalCenter;
TextRenderer.DrawText(e.Graphics, text, listView1.Font, e.Bounds, Color.Black, cFlag);
}
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
e.DrawDefault = true;
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
e.DrawDefault = true;
}
You may want to play a little with the colors or the widths..
If you have an ImageList containing images for displaying the sort order (or other things) you can add this to draw them as well:
ColumnHeader colH = listView1.Columns[e.ColumnIndex];
int ii = colH.ImageIndex;
if (ii >= 0 && ii < imageList1.Images.Count)
e.Graphics.DrawImage(imageList1.Images[ii],
e.Bounds.Width + e.Bounds.X - imageList1.ImageSize.Width, 0);
After setting OwnerDraw to true you can do other stuff like this:
Draw ListView
int sortIndex = 0;
private void listView1_DrawColumnHeader(object sender,
DrawListViewColumnHeaderEventArgs e)
{
var state = e.State == ListViewItemStates.Selected ?
VisualStyleElement.Header.Item.Hot : VisualStyleElement.Header.Item.Normal;
var sortOrder = listView1.Sorting == SortOrder.Ascending ?
VisualStyleElement.Header.SortArrow.SortedUp :
VisualStyleElement.Header.SortArrow.SortedDown;
var itemRenderer = new VisualStyleRenderer(state);
var sortRenderer = new VisualStyleRenderer(sortOrder);
var r = e.Bounds;
r.X += 1;
itemRenderer.DrawBackground(e.Graphics, r);
r.Inflate(-2, 0);
var flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter |
TextFormatFlags.SingleLine;
itemRenderer.DrawText(e.Graphics, r, e.Header.Text, false, flags);
var d = SystemInformation.VerticalScrollBarWidth;
if (e.ColumnIndex == sortIndex) //Sorted Column
sortRenderer.DrawBackground(e.Graphics,
new Rectangle(r.Right - d, r.Top, d, r.Height));
}
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
e.DrawDefault = true; /*Use default rendering*/
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
e.DrawDefault = true; /*Use default rendering*/
}
Fill ListView using Last Column
private void ListViewSample_Load(object sender, EventArgs e)
{
var otherItemWisth= this.listView1.Columns.Cast<ColumnHeader>()
.Where(x => x.Index < this.listView1.Columns.Count - 1)
.Sum(x => x.Width);
this.listView1.Columns[this.listView1.Columns.Count - 1].Width =
this.listView1.ClientSize.Width - otherItemWisth;
}
Result

How to create a toggle button inside a column in C#?

I want to create this view. But I don't know how to make this kind of button, is it feasible with C#? If so, Please help me.
For a ListView you can get something that looks like your image by
splitting the data into the Text and the Tags of each Item/Subitem
owner-drawing the ListView
storing the two images (including headroom) in two Bitmaps.
Coding the MouseDown event to bring the 'buttons' to live
Here is the code for owner-drawing.
private void listView3_DrawItem(object sender, DrawListViewItemEventArgs e)
{
Rectangle textBounds = e.Bounds; textBounds.Height /= 2;
e.Graphics.DrawImage(e.Item.Text == "True" ? bmpOn : bmpOff, e.Bounds.Location);
TextRenderer.DrawText(e.Graphics, e.Item.Tag.ToString(),
Font, textBounds, Color.Black, TFFcenter);
}
private void listView3_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
Rectangle textBounds = e.Bounds; textBounds.Height /= 2;
e.Graphics.DrawImage(e.SubItem.Text == "True" ? bmpOn : bmpOff, e.Bounds.Location);
TextRenderer.DrawText(e.Graphics, e.SubItem.Tag.ToString(),
Font, textBounds, Color.Black, TFFcenter);
}
private void listView3_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
e.DrawDefault = true;
}
The code to process clicking on a ListView is simple but not obvious:
private void listView3_MouseDown(object sender, MouseEventArgs e)
{
ListViewHitTestInfo HI = listView3.HitTest(e.Location);
if (HI.SubItem != null) HI.SubItem.Text = HI.SubItem.Text == "True" ? "False" : "True";
else if (HI.Item != null) HI.Item.Text = HI.Item.Text == "True" ? "False" : "True";
}
The DrawText call uses TextFormatFlags to center the text in the upper half:
TextFormatFlags TFFcenter =
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter;
The trick is in preparing the whole ListView.
For my test I used this routine:
ImageList il = new ImageList();
il.ImageSize = new Size(1, bmpOff.Height);
listView3.SmallImageList = il;
for (int c = 0; c < listView3.Columns.Count; c++)
listView3.Columns[c].Width = bmpOff.Width;
for (int i = 0; i < listView3.Columns.Count; i++)
{
ListViewItem lvi = new ListViewItem( (i % 2 == 0).ToString() );
for (int c = 0; c < 5; c++)
{
lvi.SubItems.Add( ( (c+i) % 2 == 0).ToString());
lvi.SubItems[c].Tag = "3/7";
}
lvi.Tag = "3/7";
listView3.Items.Add(lvi);
}
listView3.Width = listView3.Columns.Count * bmpOff.Width + 4;
Note how I use a dummy ImageList to enforce the Item heights..but while you're at it, it is probably a better idea to add the ImageList in the Designer and store the Bitmaps in it..
When you want to access/change the text displayed above the buttons you need to use the Tag of each Item/Subitem..!
It is also possible to use a DataGridView and get the same look by cell painting it.
Note that none of the solutions lends itself well to databinding as you have too many data to bind per item/cell!
In Windows Forms. (That it looks like what you are using.) You can drop a DataGridView on a form and change the ColumnType in the GridView designer to DataGridViewCheckBoxColumn. This will give you the Functionality that you are looking for.
In other words, if you dont mind the look, (But need the same functionality) you could use a Checkbox in your grid.
When you have the correct functionality : You can use the above answer from Gnqz, to get the Look of the button.

Interchange positions of two buttons

I want to replace button location (Interchange location )by black button when i click it and it is next to black button (b9=black button and lable1 is a temp for saving location).
I made this method :
void checkLocation()
{
if (ActiveControl.Location == new Point(5, 7))//-----------for button 1
{
if (b9.Location == new Point(83, 7) || b9.Location == new Point(5, 71))
{
label1.Location = ActiveControl.Location;
ActiveControl.Location = b9.Location;
b9.Location = label1.Location;
}
}// it continue for every button
and I write this code for every button_click
private void button1_Click(object sender, EventArgs e)
{
checkLocation();
}
now,some button don't work currently . what is wrong ?
by thanks from p.s.w.g
I think it is shorter and fit :
void swapLocation()
{
var tmp = ActiveControl.Location;
if((ActiveControl.Location.X==b9.Location.X)&&(Math.Abs(b9.Location.Y-ActiveControl.Location.Y)<=60))
{
ActiveControl.Location = b9.Location;
b9.Location = tmp;
}
if ((ActiveControl.Location.Y == b9.Location.Y) && (Math.Abs(b9.Location.X-ActiveControl.Location.X) <= 70))
{
ActiveControl.Location = b9.Location;
b9.Location = tmp;
}
}
Just do this to swap the locations of two controls:
void swapLocation()
{
var tmp = ActiveControl.Location;
ActiveControl.Location = b9.Location;
b9.Location = tmp;
}
Or more generally
void swapLocation(Control x, Control y)
{
var tmp = x.Location;
x.Location = y.Location;
y.Location = tmp;
}
...
swapLocation(ActiveControl, b9);
Update
It looks like you're trying to implement a version of the 15-puzzle. There are numerous ways to solve this, but to avoid a radical rewrite of your program I'd recommend this:
private int buttonWidth = 82;
private int buttonHeight = 82; // adjust these values as needed
private void button_Click(object sender, EventArgs e)
{
if ((Math.Abs(ActiveControl.Location.X - b9.Location.X) == 0 &&
Math.Abs(ActiveControl.Location.Y - b9.Location.Y) == buttonHeight) ||
(Math.Abs(ActiveControl.Location.X - b9.Location.X) == buttonWidth &&
Math.Abs(ActiveControl.Location.Y - b9.Location.Y) == 0))
{
swapLocation(ActiveControl, b9);
}
}
This basically checks to see if the ActiveControl is either directly above, below, to the left, or the right of b9, and if it is, swaps them. You can use this click handler for all buttons 1 through 8. Note this method only works with the buttons are a fixed width and height.

Categories