I have a dynamically added UserControl:
var listItem = new ListItem(/* arguments */);
listItem.Click += SetListItemColor;
panel.Controls.Add(listItem); // "panel" is FlowLayoutPanel
SetListItemColor:
private void SetListItemColor(object sender, EventArgs e)
{
var listItem = (ListItem)sender;
if (listItem.BackColor == Color.LightGray)
{
listItem.BackColor = Color.White;
}
else
{
listItem.BackColor = Color.LightGray;
}
}
No change to the color happens when I click on the UserControl. However, for test purpose, I tried to change the event to EnabledChangedand change the Enabled property, the color does change:
var listItem = new ListItem(/* arguments */);
listItem.Enabled = false;
listItem.EnabledChanged += SetListItemColor;
listItem.Enabled = true;
panel.Controls.Add(listItem);
What's the problem?
EDIT:
Since docking doesn't work in a FlowLayoutPanel, suggest setting the size of your control to the size of the panel. Set the ListItem margins to empty as below to get maximum fill. For debugging set the backcolor different to make sure you can see it:
var listItem = new ListItem(/* arguments */);
listItem.BackColor = Color.Yellow; // Debugging only
listItem.Margin = Padding.Empty;
listItem.Size = panel.Size;
listItem.Click += SetListItemColor;
Note that if the control is resized you will need to resize your ListItem again.
Related
This is my code to only make the Header of the listView bold, but it is not working, because not only the Header, but all the items are getting bold.
listView.Columns[0].ListView.Font = new Font(listView.Columns[0].ListView.Font, FontStyle.Bold);
Anyone has a solution?
Unfortunately you cannot change the header font. But you can change the font for each individual list item. The simple but hacky approach is to set ListView.Font to the bold font and change the font of every ListItem.Font to the default font.
listView.Font = _headerFont;
foreach(ListViewItem item in listView.Items)
{
item.Font = SystemFonts.DefaultFont;
}
Alternatively for full control set the OwnerDraw property to true and handle both DrawColumnHeader and DrawItem events like below:
public partial class Form1 : Form
{
private readonly Font _headerFont = new Font(SystemFonts.DefaultFont, FontStyle.Bold);
public Form1()
{
InitializeComponent();
listView.OwnerDraw = true;
listView.DrawColumnHeader += DrawColumnHeader;
listView.DrawItem += DrawItem;
}
private void DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
// Draw default background
e.DrawBackground();
// Draw text in a different font
TextRenderer.DrawText(e.Graphics,
e.Header.Text,
_headerFont,
e.Bounds,
SystemColors.ControlText,
TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
}
private void DrawItem(object sender, DrawListViewItemEventArgs e)
{
// Use defaults for Items
e.DrawDefault = true;
}
}
The example above shows how it works, but in a real world application you also have to draw dependent on the item's state like in the more comprehensive example in the .NET docs
Using the answer of Christian Held, I come up with the next solution:
Put this in the constructor of the form:
List<ColumnHeader> columns = new List<ColumnHeader>
{
new ColumnHeader{Text = "ColumnOne", TextAlign = HorizontalAlignment.Left},
new ColumnHeader{Text = "ColumnTwo", TextAlign = HorizontalAlignment.Left},
new ColumnHeader{Text = "ColumnThree", TextAlign = HorizontalAlignment.Left}
};
MyListView.Font = new Font(SystemFonts.DefaultFont, FontStyle.Bold);
columns.ForEach(col => MyListView.Columns.Add(col));
MyListView.View = View.Details;
After that, when you fill with data your ListView, you must set the font for every record added:
foreach (MyData myData in MyDatas){
listViewItem = new ListViewItem(new string[]
{
myData.Data1,
myData.Data2,
myData.Data3
});
listViewItem.Font = SystemFonts.DefaultFont;
MyListView.Items.Add(listViewItem);
}
And it works fine for me. If you want to change the backcolor or other things in the font of the data, just change the SystemFonts.DefaultFont for some font that you like, something like
var myFont = new Font(...your details here....);
Here is my code:
RadScrollablePanel panel = new RadScrollablePanel() { AutoScroll = true, Dock = DockStyle.Fill};
pnlclp.PanelContainer.Controls.Add(panel);
foreach (var date in dates)
panel.Controls.Add(new ucDetails() { Dock = DockStyle.Left });
I'm adding some controls inside a RadScrollablePanel and then adding it into a PanelContainer.
Everything works great. If I add so many controls inside the RadScrollablePanel which is not visible in first look, the scroll bar will be shown as well.
But If I change the DockStyle.Left to DockStyle.Right in foreach loop, after loading the controls, it will not show the scroll bar and it is strange and I can not find any reason or solution to solve this issue.
I even try to change the RightToLeft property of RadScrollablePanel. but no success :(
Any suggestion?
Following the provided information, I have prepared a sample project to test the behaior in RadScrollablePanel.
I have logged it in our feedback portal by creating a public thread. You can track its progress, subscribe for status changes and add your comments on the following link: https://feedback.telerik.com/winforms/1453253-radscrollablepanel-missing-scrollbar-when-there-is-no-enough-space-to-display-the-content-controls
I hope this information helps.
To work around this problem of the standard Microsoft WinForms Panel, I can suggest docking all the UserControls to the Left and use an empty Panel that occupies all the available space on the left of the form, so exactly the same behavior as all UserControls are docked to the Right. When the size of the form is changed adjust the width of the empty panel. The described approach is illustrated with the code below:
public partial class Form1 : Form
{
UserControl1[] userControls;
RadScrollablePanel parentPanel;
Panel spacePanel;
public Form1()
{
InitializeComponent();
new Telerik.WinControls.RadControlSpy.RadControlSpyForm().Show();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.parentPanel = new RadScrollablePanel();
this.parentPanel.Dock = DockStyle.Fill;
this.parentPanel.BackColor = Color.Yellow;
this.Controls.Add(this.parentPanel);
this.parentPanel.AutoScroll = true;
int count = 10;
this.userControls = new UserControl1[count];
for (int i = 0; i < count; i++)
{
this.userControls[i] =
new UserControl1()
{
Dock = DockStyle.Left,
BackColor = Color.FromKnownColor((KnownColor)(i + 50))
};
this.parentPanel.Controls.Add(this.userControls[i]);
}
this.spacePanel = new Panel();
this.spacePanel.Dock = DockStyle.Left;
this.parentPanel.Controls.Add(this.spacePanel);
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
if (this.spacePanel != null)
{
int lastPanelWidth = this.parentPanel.Width;
foreach (Control control in this.parentPanel.PanelContainer.Controls)
{
if (control.Dock == DockStyle.Left && control != this.spacePanel)
{
lastPanelWidth -= control.Width;
}
}
if (lastPanelWidth < 0)
{
lastPanelWidth = 0;
}
this.spacePanel.Width = lastPanelWidth;
}
}
}
I am unable to show tooltips on ListView subitems. Involved implementation is:
ListView sqlView = new ListView() { Dock = DockStyle.Fill, View = View.Details, MultiSelect = true, FullRowSelect = true, HeaderStyle = ColumnHeaderStyle.Nonclickable, GridLines = true };
...
sqlView.ShowItemToolTips = true;
sqlView.MouseMove += sqlView_MouseMove;
...
// filled in foreach, don't worry it's correct here ;)
item.SubItems[columnIndex].Text = "✔";
item.SubItems[columnIndex].Tag = ("via: '" + sqlEntry.Login + "'");
Mouse event handler method:
void sqlView_MouseMove(object sender, MouseEventArgs e)
{
ListView sqlView = ((ListView)sender);
ListViewItem item = sqlView.GetItemAt(e.X, e.Y);
ListViewHitTestInfo info = sqlView.HitTest(e.X, e.Y);
if (item != null && info.SubItem != null && info.SubItem.Tag != null)
{
ToolTip tt = new ToolTip();
//tt.ShowAlways = true; - no effect
//tt.Active = true; - no effect
tt.SetToolTip(sqlView, (String)info.SubItem.Tag);
}
}
Events are firing. Subitems Tags are filled properly. No Tooltip shown. Why?
Thx for help.
Don't create a new ToolTip() each time through. Just create one and reuse it.
I'm having a problem with C# buttons in Windows Forms.
I've create a number of buttons programmatically and add them to a form afterwards.
Interestingly, every modification to those buttons (location and size) except for the modification of the BackColor is readily executed. Only the button's color remains unchanged.
The code looks something like this:
public class SimpleSortAlgDisplayer : ISortAlgDisplayer
{
#region ISortAlgDisplayer Member
void ISortAlgDisplayer.Init(int[] Data)
{
this.DataLength = Data.Length;
this.DispWin = new CurrentSortStateWin();
this.DispWin.Show();
this.DispWin.Size = new Size(60 + (10 * this.DataLength), 120);
this.myArrayElements = new Button[this.DataLength];
for (int i = 0; i < this.DataLength; i++)
{
this.myArrayElements[i] = new Button();
//begin of series of invoked actions
this.myArrayElements[i].Size=new Size(5,(int)(((80)*(double)Data[i])/1000));
this.myArrayElements[i].Location = new Point(30 + (i * 10), 90-(this.myArrayElements[i].Size.Height));
this.myArrayElements[i].Enabled = true;
this.myArrayElements[i].BackColor = Color.MidnightBlue;
this.myArrayElements[i].UseVisualStyleBackColor = true;
this.DispWin.Controls.Add(this.myArrayElements[i]);
this.myArrayElements[i].Refresh();
}
}
Ideas anyone?
A similar question was asked here but the answers to it were not very helpful:
Trying to use Invoke gives me the run-time error that DispWin is not yet created.
Setting UseVisualStyleBackColor to false changes nothing.
Setting BackColor and ForeColor or Showing DispWin only after adding and formatting the Buttons also had no effect.
Where am I going wrong?
You are trying to set up the color, but then you override it saying UseVisualStyleBackColor = true
if you want to use your custom color, you need to set UseVisualStyleBackColor to false or the color will only be applied to the button upon mouse over.
a simple test uploaded to GitHub
public partial class mainForm : Form
{
Random randonGen = new Random();
public mainForm()
{
InitializeComponent();
}
private void mainForm_Load(object sender, EventArgs e)
{
populate();
}
private void populate()
{
Control[] buttonsLeft = createButtons().ToArray();
Control[] buttonsRight = createButtons().ToArray();
pRight.Controls.AddRange(buttonsRight);
pLeft.Controls.AddRange(buttonsLeft);
}
private List<Button> createButtons()
{
List<Button> buttons = new List<Button>();
for (int i = 1; i <= 5; i++)
{
buttons.Add(
new Button()
{
Size = new Size(200, 35),
Enabled = true,
BackColor = GetColor(),
ForeColor = GetColor(),
UseVisualStyleBackColor = false,
Left = 20,
Top = (i * 40),
Text = String.Concat("Button ", i)
});
}
return buttons;
}
private Color GetColor()
{
return Color.FromArgb(randonGen.Next(255), randonGen.Next(255), randonGen.Next(255));
}
}
result
If FlatStyle for button is set to System, it will not show any backcolor rather use backcolor from template of system colors.
Make sure you do not have a BackgroundImage set. This overrides the BackColor.
In the properties window for Button. Look for 'FlatStyle' property and change it from 'System' to 'Flat', 'Standard' or 'Popup' and you will be able to see the button color change. I just fixed my issue with this.
I have the following code where a click event will dynamically create additional Canvas to the WrapPanel, and each Canvas contains a TextBox and a Button. Once the Button on one Canvas is click, TextBox.Text and Button.Content change from "Foo" to "Jesus".
The below code works, but it's not ideal. Because each property Change ("Foo" to "Jesus), I have to run a loop. I have to run two loops just to change the text on the TextBox and Button. Is there a direct way to change the Properties other then a Loop? My actually application contains 30+ controls in a Canvas, I don't want to run 30+ loops each time just to change some text.
List<Canvas> cvList = new List<Canvas>();
List<TextBox> tbList = new List<TextBox>();
List<Button> FooList = new List<Button>();
WrapPanel wp = new WrapPanel();
private void createbtn1_Click(object sender, RoutedEventArgs e)
{
Canvas cv = new Canvas();
StackPanel sp = new StackPanel();
TextBox tb = new TextBox();
Button Foo = new Button();
sp.Orientation = Orientation.Vertical;
sp.Children.Add(tb);
sp.Children.Add(Foo);
cv.Children.Add(sp);
wp.Children.Add(cv);
cvList.Add(cv);
tbList.Add(tb);
FooList.Add(Foo);
cv.Width = 100;
cv.Height = 100;
tb.Text = "#" + (cvList.IndexOf(cv)+1);
tb.Width = 50;
tb.Height = 30;
Foo.Content = "Foo";
Foo.Click += destroy_Click;
}
private void Foo_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
var bIndex = FooList.IndexOf(b);
foreach (TextBox t in tbList)
{
if (tbList.IndexOf(t) == bIndex)
{
t.Text = "Jesus";
}
}
foreach (Button f in FooList)
{
if (FooList.IndexOf(t) == bIndex)
{
t.Content = "Jesus";
}
}
}
Just access the text boxes by index and set the content of the button directly:
if(bIndex < tbList.Count && bIndex != -1)
tbList[bIndex].Text = "Jesus";
if(b != null && bIndex != -1)
b.Content = "Jesus";
why can't you just get the item at the index and set that items text:
tbList[bindex].Text="Jesus";
As for setting the buttons content, you already have the button from the click event, so just use that:
b.Content = "Jesus";
You current code just loops through each item in the list and gets the index of the item and sees if it is the index you want. Accessing by the indexer of the list directly will give you what you want.
You will probably want to do some error checking, but that is not currently done in your existing code either.
Some info on using indexers from MSDN