I want to change the property Background of many Buttons in WP7.
Can I write something like this:
Foreach (var item in (this.Content as Panel).Children)
{
If (Element is Button)
{
Element.Background = Color.red;
}
}
But this doesen't work,
Element.Background doesen't exist...
Anyone know how to fix it???
try this
//to be on the safe side first check
if(this.Content == null || !(this.Content is Panel)
return;
foreach (var item in (this.Content as Panel).Children)
{
if (item is Button)
{
Button b = item as Button;
b.Background = new SolidColorBrush(Colors.Red);
}
}
Can you try it with
Element.BackColor = Color.Red
instead of
Element.Background = Color.Red
Instead of looping through the controls, try binding their BackColor properties to something, be it a class that implements INotifyPropertyChanged with a property that returns a SolidColorBrush, another control's BackColor property, or whatever you choose to bind to. This can be done in silverlight without having to loop through the controls. Let the system manage the control appearance instead of writing it yourself.
Related
Copy TabControl Tab Yes I have checked this.
I'm trying to duplicate a tabcontol but this tab should have it's own 'behaviour'.
TabControl tc = TC_Fields;
TabPage tpOld = tc.TabPages[0];
TabPage tpNew = new TabPage();
fields += 1;
tpNew.Name = "Field_" + fields;
tpNew.Text = "Field-" + fields;
foreach (Control c in tpOld.Controls)
{
Control cNew = (Control) Activator.CreateInstance(c.GetType());
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(c);
foreach (PropertyDescriptor entry in pdc)
{
object val = entry.GetValue(c);
if (entry.Name == "Name")
{
val = (String) val + fields;
}
entry.SetValue(cNew, val);
}
tpNew.Controls.Add(cNew);
}
tc.TabPages.Add(tpNew);
I've tried above code, so it gives the new control a new "id", yet I am still not able to click the controls in the new tab, and they only mimic what's in the first tab.
Is there a way I can copy all controls yet not mimic the controls they were copied of?
Your code has at least two issues not related to the actual question. Let's fix two of them first:
You set all properties even those you should not set; most notably you should not touch the "WindowTarget" property! It is for internal use only and messing with it will stop at least some controls from working. I found I couldn't check a CheckBox, for example.
Your code only will create visible controls if the orginal TabPage is also the current one. All controls on all other pages are invisible and if you try to clone any other TabPage all control will be added just fine but remain invisible.
Let's add a filter :
if(entry.Name != "WindowTarget") entry.SetValue(cNew, val);
and make the new controls visible:
cNew.Visible = true;
tpNew.Controls.Add(cNew);
Note that this is a simplistic solution as it will also make those controls visible that were invisible originally. You could instead show the page you want to clone or make a list of invisible controls; with their names you could find the cloned counterparts..
The last issue is also important but goes beyond the question: The code only clones the controls directly on the page, not any neseted controls (like RadioButtons in a GroupBox !). To do so you would have to write a recursive version!
Now for the actual question: How can you give the cloned controls their own behaviour?
After cloning all their properties they are like freshly added controls, i.e. they have no event handlers at all.
So you need to
write new event handlers for the new controls' events
hook them up
While this is not really hard there are quite a few problems..
We know the naming scheme and so we can know which controls we want to supply with events. The event names are free to choose but to hook them up we need to know which of the new controls we are dealing with..
Here is and example that hooks up the first clone of a Button cb_hello with a Click event:
if (cNew.Name == "cb_hello1") cNew.Click += buttonNew_Click;
The code in the event demonstrates more issues:
private void buttonNew_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
Console.WriteLine(btn.Name + " says hiho");
btn.Parent.Controls["panel41"].BackColor = Color.ForestGreen;
((RadioButton)btn.Parent.Controls["radioButton11"]).Checked = true;
}
While casting the sender to Button is quite normal we run into trouble when we try to access any of the controls we have just cloned:
Since they were dynamically created we can't access any of them with variables. Instead we need to use the TabPage's Controls collection to find them.
We can set BackColor or any other property inherited from Control but to set RadioButton.Checked we need to cast to RadioButton; and we need to access the control from the Controls collection, for example by its Name.
Once you upgrade to recursive cloning you will want to use Controls.Find(name, true) to include the nested controls..
As you can see it can be done but it will take a little more effort than coding the original controls and the code feels somewhat fragile as we introduce hidden dependencies: All those references to the cloned names rely on the original names!
Final note: While the regular properiets get cloned, the data and structure containers do not, i.e. all Items, ListViewItems or Rows, Columns collections etc, etc are not cloned!
TabControl tc = TC_Fields;
TabPage tpOld = tc.SelectedTab;
TabPage tpNew = new TabPage();
fields += 1;
tpNew.Name = "Field_" + fields;
tpNew.Text = "Field-" + fields;
foreach (Control c in tpOld.Controls)
{
Control cNew = (Control) Activator.CreateInstance(c.GetType());
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(c);
foreach (PropertyDescriptor entry in pdc)
{
object val = entry.GetValue(c);
if (entry.Name == "Name")
{
val = (String) val + fields;
}
else if (entry.Name == "Location" || entry.Name == "Text" || entry.Name == "Bounds" || entry.Name == "Enabled"
|| entry.Name == "Visible" || entry.Name == "Checked" || entry.Name == "CheckState")
{
//Nothing to do, but do continue!
}
else if (entry.Name == "Controls")
{
Control.ControlCollection controllsInside = (Control.ControlCollection) val;
foreach (Control controllInside in controllsInside)
{
Control cNewInside = (Control) Activator.CreateInstance(controllInside.GetType());
PropertyDescriptorCollection pdcInside = TypeDescriptor.GetProperties(controllInside);
foreach (PropertyDescriptor entryInside in pdcInside)
{
object valInside = entryInside.GetValue(controllInside);
if (entryInside.Name == "Name")
{
valInside = (String) valInside + fields;
}
else if (entryInside.Name == "Location" || entryInside.Name == "Text" || entryInside.Name == "Bounds" || entryInside.Name == "Enabled"
|| entryInside.Name == "Visible" || entryInside.Name == "Checked" || entryInside.Name == "CheckState")
{
//Nothing to do, but do continue!
}
else
{
continue;
}
entryInside.SetValue(cNewInside, valInside);
}
cNew.Controls.Add(cNewInside);
}
}
else
{
continue;
}
entry.SetValue(cNew, val);
}
tpNew.Controls.Add(cNew);
}
tc.TabPages.Add(tpNew);
TC_Fields.SelectedIndex = fields - 1;
This will also do the trick :) #TaW already put the solution on there, but here is some copy paste code :)
foreach (Control c in this.Controls)
{
if (c is TextBox && c.Text.Length==0)
{
// [Associatedlabel].ForeColor = System.Drawing.Color.Red;
err = true;
}
instead of [Associatedlabel], I want to associate each textbox to label, so eventually all labels near the textbox that are empty will be red, how it can be done?
Thanks.
There is no fantastic way to find the label control back from the textbox. Using the form's GetChildAtPoint() method is something you can make easily work but are going to regret some day. Naming helps, like FooBarLabel matches FooBarTextBox. Now you can simply use the Controls collection to find the label back:
var label = (Label)this.Controls[box.Name.Replace("TextBox", "Label")];
But Winforms solves many problems by simple inheritance. Add a new class to your project and paste this code:
using System;
using System.Windows.Forms;
class LabeledTextBox : TextBox {
public Label Label { get; set; }
}
Compile and drop the new control from the top of the toolbox. Set the Label property in the designer, just pick it from the dropdown list. Boomshakalaka.
You can first manually set your TextBox's Tag property to these labels. Tag is meant to contain user-defined data, so you can place any object there. Then you can do simply:
foreach (Control c in this.Controls)
{
if (c is TextBox && c.Text.Length==0 && c.Tag is Label)
{
((Label)c.Tag).ForeColor = System.Drawing.Color.Red;
err = true;
}
}
This is the simplest solution, but a few more sophisticated exists though.
Creating a custom composite control consisting of a label, textbox and custom behavior;
Creating a control deriving from a textbox, which stores information about label it is connected with (as Hans Passant suggests)
Creating a Dictionary<TextBox, Label> or Dictionary<Control, Label>, which allows resolving such matters in runtime (variation on Steve's idea).
I suppose that you are using WinForms. In this environment you don't have any built-in functionality that associate a label to a textbox. So you need to build your own association.
This could be done creating a dictionary in the constructor of your code
public class MyForm : Form
{
private Dictionary<string, Label> assoc = new Dictionary<string, Label>();
public MyForm()
{
// Key=Name of the TextBox, Value=Label associated with that textbox
assoc.Add("textbox1", Label1);
assoc.Add("textbox2", Label2);
assoc.Add("textbox3", Label3);
}
}
.....
foreach (TextBox t in this.Controls.OfType<TextBox>())
{
if(t.Text.Length == 0)
{
assoc[t.Name].ForeColor = System.Drawing.Color.Red;
err = true;
}
else
assoc[t.Name].ForeColor = ??? system forecolor ???
}
I have a ComboBox in a WPF application which contains a list and 'OK' button. I would like the ComboBox popup area to be closed when a user click on the OK button which in the ComboBox.
(I want the click event to change the property: IsDropDownOpen of the ComboBox
How can I cause an internal content to close its container?
You could try replacing the Button with a ToggleButton and bind the ToggleButton.IsChecked property to the ComboBox.IsDropDownOpen property using and 'inverse bool Converter' (a Converter class that returns the opposite of the bool input value.)
The only problem with this is that you would need to 'un-toggle' the ToggleButton each time the ComboBox drop down opened.
You could use the Logical/Visual Tree to get the containing ComboBox:
DependencyObject prop = sender as DependencyObject;
while (prop != null && !(prop is ComboBox))
{
prop = LogicalTreeHelper.GetParent(prop);
}
if (prop != null)
{
((ComboBox) prop).IsDropDownOpen = false;
}
Of course thats just a quick and dirty solution and should be cleaned up. ;)
I have a Panel and two LinkLabels added on the panel and a treeview.
now in the panel_Paint event i want that the linklabel colors become white and background color of treeview turns black.
how do i do this?
the below code works only when there is no tree view in the panel but when i add a treeview also in the panel then it says :
Unable to cast object of type 'System.Windows.Forms.TreeView' to type 'System.Windows.Forms.LinkLabel'.
foreach (LinkLabel link in panel1.Controls)
{
link.LinkColor = Color.White;
}
Your panel contains all the controls - one of them is a TreeView which cannot be cast into a LinkLabel. In your loop you need to check the type of the control like this:
foreach (Control control in panel1.Controls)
{
if (control is LinkLabel)
{
... set link color
}
else if (control is TreeView)
{
... set background
}
}
Alternatively if you only have one LinkLabel and one TreeView you would not need a loop - just access them by name like you did with panel1
Try this:
foreach (Control ctrl in panel1.Controls)
{
LinkLabel link = ctrl as LinkLabel;
if(link != null)
link.LinkColor = Color.White;
}
Your getting the error because your trying to cast all controls in panel1 to a LinkLabel. You need to try something like this
foreach (Control control in panel1.Controls)
{
if (control.GetType() == typeof(LinkLabel))
{
LinkLabel link = (LinkLabel)control;
link.LinkColor = Color.White;
}
}
Hope this helps.
Edit: I knew there was a method but wasn't sure 100% of the name or syntax. See below an improved answer.
foreach (LinkLabel link in panel1.Controls.OfType<LinkLabel>())
{
link.LinkColor = Color.White;
}
Hope this is better for you.
I would need to know how to let the programatically selected node make graphically in the state "selected" like the user clicked on it. SelectedNode only makes this one internally selected. Thank you very much!
The reason it does not show as highlighted is due to the tree view not having focus. This is in a button click event on my test form:
TreeView1.SelectedNode = TreeView1.Nodes(2);
TreeView1.Focus();
Which highlights the node properly. if you remove the Focus(); call it doesn't highlight until you click into the tree view (anywhere in the tree view, not necessarily on to the node that you want to be selected).
TreeView1.SelectedNode.BackColor = SystemColors.HighlightText; // This will work
Above solutions will only set the focus on it but will not change the highlight view of it.
This works for me for .net 3.5:
Set the treeview component's DrawMode property to: OwnerDrawAll
Then in the DrawNode event write the following:
if (((e.State & TreeNodeStates.Selected) != 0) && (!MyTreeView.Focused))
e.Node.ForeColor = Color.Blue;
else
e.DrawDefault = true;
And in the BeforeSelect event have:
if (MyTreeView.SelectedNode != null)
MyTreeView.SelectedNode.ForeColor = Color.Black;
e.Node.ForeColor = Color.Blue;
I don't know if it helps you or not but check the taborder of the the page and make sure that the tree view control has tab order of 0
Here is what I got to work:
void myProcedure()
{
// Hookup a DrawMode Event Handler
this.myTV.DrawNode += myTV_DrawNode;
// Set DrawMode and HideSelection
this.myTV.DrawMode = TreeViewDrawMode.OwnerDrawText;
this.myTV.HideSelection = false;
// Make sure the TreeView has Focus
this.myTV.Focus();
// Make sure the TreeView is Selected
this.myTV.Select();
// If the TreeView has a Node, I want to select the first Node to demonstrate.
if (this.myTV.Nodes.Count > 0)
{
// Make sure the node is visible
this.myTV.Nodes[0].EnsureVisible();
// Make sure the Node is Selected
this.myTV.SelectedNode = myTV.Nodes[0];
}
// Make sure the SelectedNode IS the Node that we programmatically want to select.
textBox1.Text = this.myTV.SelectedNode.Text;
// if we display sanityCheck1 string, it actually is the correct node.text
// Make sure .NET runtime knows the Node is selected
textBox1.Text += " is Selected = " + this.myTV.SelectedNode.IsSelected.ToString();
}
Following up: laalto answered the How to HighLight the TreeView.Node. The following code in the DrawNode Event Handler, from samball's answer, properly highlights the TreeView.Node based on its Selected State.
private void myTV_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
// first, let .NET draw the Node with its defaults
e.DrawDefault = true;
// Now update the highlighting or not
if (e.State == TreeNodeStates.Selected)
{
e.Node.BackColor = SystemColors.Highlight;
e.Node.ForeColor = SystemColors.HighlightText;
}
else
{
e.Node.BackColor = ((TreeView)sender).BackColor;
e.Node.ForeColor = ((TreeView)sender).ForeColor;
}
}
Platform = C# .NET 4.5 in Windows 10, Visual Studio 2015
TreeView1.SelectedNode = TreeView1.Nodes(2);
this.ActiveControl = TreeView1;
This works for me (.net 4.7)
The underlying Win32 control supports this (think it's TVIS_DROPHILITED), but I can't see the same functionality exposed through the TreeView control.
As theraneman says, you could fake it with the TreeNode.ForeColor and BackColor properties...
I had an similar issue and wanted to have a TreeView node selected (highlighted) on form load.
Maybe someone has the same problem, too.
I first tried Pondidum's solution. Without success.
But then I found the solution in another thread: Simply set the TabIndex of the TreeView to 0.
In that case you don't need to set the focus. Just choose the node that should be selected by using SelectedNode and set the TabIndex. That's it.
Not sure, but can you not change the background color of that node?