Error adding new TextBlock to Canvas in WPF - c#

I want to add text to my canvas in WPF. The code runs until I want to add the TextBlock to the canvas as a child, giving me this:
"Specified element is already the logical child of another element. Disconnect it first."
Here is the relevant code:
private void txtbItemName_TextChanged(object sender, TextChangedEventArgs e)
{
TextBlock txtItemName = new TextBlock();
txtItemName.Text = txtbItemName.Text;
txtItemName.Margin = new Thickness(10, 10, 0, 0);
cnvImage.Children.Remove(txtItemName);
cnvImage.Children.Add(txtbItemName); //The error screen showed up when running this line
}

You have an error. You are trying to remove the new item and add existing one.
Here is a right code for you:
TextBlock txtItemName = new TextBlock();
txtItemName.Text = txtbItemName.Text;
txtItemName.Margin = new Thickness(10, 10, 0, 0);
cnvImage.Children.Remove(txtbItemName);
cnvImage.Children.Add(txtItemName);

It seems that your txtbItemName is already a child of an element in your XAML i suppose (can't see your XAML). because you have already created this element in your xaml it won't let you add it to the canvas.

I found it: I indeed tried to place an object that was already present. I accidentally placed an existing textBOX (txtb) instead of a textBLOCK (txt). Thanks for the help though!

Related

Stepping through controls in a wrappanel

I have a bunch of controls located in a wrappanel in a WPF app that are procedurally created. The first control is a label followed by a bunch of comboboxes and a checkbox. The user clicks a button and a new row of controls are added. This worked fine. Then I decided to make the label a bit more attractive by giving it a red circle as a background and the label was nested in a grid with the red circel behind the label that simply listed the row number. This worked fine. And I use to step through all the controls with this block:
foreach (Control item in WrapPanelItems.Children)
{
if (item.GetType() == typeof(CheckBox))
{
RowCounter++;
}
}
now suddenly this block of code fails with this error: 'Unable to cast object of type 'System.Windows.Controls.Grid' to type 'System.Windows.Controls.Control'.'
So I suspect the grid isnt a conventional item and the code fails. But how would I then iterate through the controls without the app crashing and still iterate through all the conventional controls ontop of it?
Here is the code for how I style and add the label.
Grid MyGrid= new Grid();
Ellipse myEllipse = new Ellipse();
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(255, 107, 142, 35);
myEllipse.Fill = mySolidColorBrush;
myEllipse.Width = 20;
myEllipse.Height = 20;
MyGrid.Children.Add(myEllipse);
Label LabelCounter = new Label();
LabelCounter.Content = RowCount.ToString();
MyGrid.Children.Add(LabelCounter);
LabelCounter.VerticalAlignment = VerticalAlignment.Center;
LabelCounter.HorizontalAlignment = HorizontalAlignment.Center;
WrapPanelItems.Children.Add(MyGrid);
And also a second question. Suppose I want to change the text on the label... how would I get to the label if its nested in a grid? Can you just change the content directly when the FOR loop picks up the grid? Or should you then say all children of grid when the grid is identified in the FOR loop?
tx
Grid is not a System.Windows.Controls.Control so this line throws an exception:
foreach (Control item in WrapPanelItems.Children)
You can replace Control with UIElement to avoid this error.
According to MSDN:
public class Grid : System.Windows.Controls.Panel, System.Windows.Markup.IAddChild

RichTextBox not showing the text

I am trying to create a Bitmap from a RichTextBox and set it as the background image for a panel, but unfortunately the text is not shown.
Bitmap l_bitmap = new Bitmap(m_control.Width, m_control.Height);
m_control.DrawToBitmap(l_bitmap, new Rectangle(0, 0, l_bitmap.Width, l_bitmap.Height));
m_panel.BackgroundImage = l_bitmap;
m_panel.Refresh();
m_control is my RichTextBox. When I debug, I can see that the control contains the text I wrote, but the bitmap just shows an empty RichTextBox.
I use the same code for other types of controls (Button, CheckBox, TextBox...). The text is shown with no problems.
Well you are trying to create a bitmap from the control. The text you put in there isn't the control, so it won't bother to chow it as bitmap. Try to create a picture from screen (like a screenshot).
Example:
Graphics gr = Graphics.FromImage(l_bitmap);
gr.CopyFromScreen(m_control.PointToScreen(Point.Empty), point.Empty, m_control.Size);
This will make a bitmap from your given points. This will additional show you the text.
EDIT
Maybe you can use this instead. In addition to your idea, I simply put a label onto my panel. (L for Label and P for Panel)
As you can see, the label is empty because I cleared the Text property. Now, when you click one of the buttons below the panel, it will update the label.Text propertie and there will be the text you gave the control.
Here is some example:
As you can see, the label shows the Name of the control. Completly custom as you can see on my source code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public RichTextBox tmpRtf = new RichTextBox();
//Poor button name incoming...
private void button1_Click(object sender, EventArgs e)
{
if (tmpRtf == null)
tmpRtf = new RichTextBox();
//You can add any text here and it will be shown on the label.
this.tmpRtf.Text = "Richtextbox";
this.UpdatePanel(this.tmpRtf);
}
//Custom method to update the panel for any control. Can pobably be done way better than this, but hey.
private void UpdatePanel(object pControl)
{
//Checks if control is a rtf
if(pControl is RichTextBox)
{
//This is your code! Ay.
Bitmap l_bitmap = new Bitmap(this.panel1.Width / 2, this.panel1.Height / 2);
(pControl as RichTextBox).DrawToBitmap(l_bitmap, new Rectangle(0, 0, l_bitmap.Width, l_bitmap.Height));
this.tmpRtf.BackColor = Color.LightGray;
this.panel1.BackgroundImage = l_bitmap;
this.panel1.BackgroundImageLayout = ImageLayout.Center;
this.labelControlName.Text = this.tmpRtf.Text;
this.panel1.Refresh();
}
}
}
Its not possible to show text on a control thats not visualized. But you can build a workaround! Or, instead of taking a picture you can simply create the control on top of it, that will also show the Text and maybe the user can test it (e.g. click on buttons, look at the control behaviour).
Hopefully this is something to get you inspired that there are always more ways to accomplish.

c# winforms dock fill tree-view make it disappear

I have a winforms application. In my application I have a user control which I loaded programmatically.
Inside this user-control I have tree view that also will be loaded with items programmatically. My problem is that I want to make my tree-view take the whole size of its parent.
What I have tried
I set the user-control Dock property to DockStyle.Fill to make it take the size of its parent.
I have done the same for the tree-view Dock property; set it to DockStyle.Fill.
What I get
The user-control takes the full size as expected but the tree-view looks like it is hidden. I checked the height, and I noticed it's 0. When I tried to change the height while it has DockStyle.Fill I can't, it changes back to 0.
Any ideas?
Update
The auto generated code for the tree-view:
private void InitializeComponent()
{
this.btnAddServer = new System.Windows.Forms.Button();
this.pnlServersContainer = new System.Windows.Forms.FlowLayoutPanel();
this.treeViewServers = new System.Windows.Forms.TreeView();
this.pnlServersContainer.SuspendLayout();
this.SuspendLayout();
//
// btnAddServer
//
this.btnAddServer.Location = new System.Drawing.Point(89, 478);
this.btnAddServer.Name = "btnAddServer";
this.btnAddServer.Size = new System.Drawing.Size(107, 23);
this.btnAddServer.TabIndex = 3;
this.btnAddServer.Text = "Add New Server";
this.btnAddServer.UseVisualStyleBackColor = true;
this.btnAddServer.Click += new System.EventHandler(this.btnAddServer_Click);
//
// pnlServersContainer
//
this.pnlServersContainer.AutoScroll = true;
this.pnlServersContainer.Controls.Add(this.treeViewServers);
this.pnlServersContainer.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlServersContainer.Location = new System.Drawing.Point(0, 0);
this.pnlServersContainer.Name = "pnlServersContainer";
this.pnlServersContainer.Padding = new System.Windows.Forms.Padding(8, 20, 0, 0);
this.pnlServersContainer.Size = new System.Drawing.Size(318, 463);
this.pnlServersContainer.TabIndex = 2;
//
// treeViewServers
//
this.treeViewServers.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeViewServers.Location = new System.Drawing.Point(11, 23);
this.treeViewServers.Name = "treeViewServers";
this.treeViewServers.Size = new System.Drawing.Size(275, 0);
this.treeViewServers.TabIndex = 0;
this.treeViewServers.DoubleClick += new System.EventHandler(this.treeViewServers_DoubleClick);
//
// ucServersList
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Controls.Add(this.btnAddServer);
this.Controls.Add(this.pnlServersContainer);
this.Name = "ucServersList";
this.Padding = new System.Windows.Forms.Padding(0, 0, 0, 60);
this.Size = new System.Drawing.Size(318, 523);
this.Load += new System.EventHandler(this.ucServersList_Load);
this.pnlServersContainer.ResumeLayout(false);
this.ResumeLayout(false);
}
I recommend to open Document outline editor in Visual Studio.
This shows all controls in their hierarchical order as tree.
It lets you also drag & drop the controls to the right place.
Open it with View > Other windows > Document outline.
You may fix your problem when looking at the controls order.
I have figured it out. but still don't know why this happened!
my tree-view was inside FlowLayoutPanel not Panel. When i changed it to Panel everything goes fine. that's it!
The problem might be that you have added several items to the same parent control, and then when you fill the parent dock with one of them, the behaviour would not be what you expect.
Use a splitcontainer. And when you want to fill out the dock, make sure your control belongs to two differnt panels of a splitcontainer.
See this for an concrete example.
Is there any specific reason why you use FlowLayoutPanel?
It seems that the FlowLayoutPanel does not deal with any other than Dock.None.
I think you should use a simple Panel for this application, because it does not resize the contained controls - the Dock property behaves as expected.
Replacing the FlowLayoutPanel with a Panel will fix your problem.
This is a super old question... but since there are no accepted answers I’ll give it a go.
This happened to me when my Control was set to autosize. Either removing autosize or specifying a minimum height could solve this issue.

How can I include icons in my ListBox?

I know that similar questions have already been asked here before, but they all lead to the same codeproject article that doesn't work. Does anybody know of a working ListBox with icons?
Will a ListView work for you? That is what I use. Much easier and you can make it look just like a ListBox. Also, plenty of documentation on MSDN to get started with.
How to: Display Icons for the Windows Forms ListView Control
The Windows Forms ListView control can display icons from three image
lists. The List, Details, and SmallIcon views display images from the
image list specified in the SmallImageList property. The LargeIcon
view displays images from the image list specified in the
LargeImageList property. A list view can also display an additional
set of icons, set in the StateImageList property, next to the large or
small icons. For more information about image lists, see ImageList
Component (Windows Forms) and How to: Add or Remove Images with the
Windows Forms ImageList Component.
Inserted from How to: Display Icons for the Windows Forms ListView Control
If you don't want to change ListBox to a ListView you can write a handler for DrawItemEvent. for example:
private void InitializeComponent()
{
...
this.listBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.listBox_DrawItem);
...
}
private void listBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1)
return;
// Draw the background of the ListBox control for each item.
e.DrawBackground();
var rect = new Rectangle(e.Bounds.X+10, e.Bounds.Y+8, 12, 14);
//assuming the icon is already added to project resources
e.Graphics.DrawIconUnstretched(YourProject.Properties.Resources.YouIcon, rect);
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(),
e.Font, Brushes.Black, new Rectangle(e.Bounds.X + 25, e.Bounds.Y + 10, e.Bounds.Width, e.Bounds.Height), StringFormat.GenericDefault);
// If the ListBox has focus, draw a focus rectangle around the selected item.
e.DrawFocusRectangle();
}
you can play around with the rectangle to set the location of the icon right
If you're stuck working in WinForms, then you'll have to owner-draw your items.
See the example for the DrawItem event.
A little different approach - don't use a list box.
Instead of using that control that bounds me to its limited set of properties and methods I am making a listbox of my own.
It's not as hard as it sounds:
int yPos = 0;
Panel myListBox = new Panel();
foreach (Object object in YourObjectList)
{
Panel line = new Panel();
line.Location = new Point(0, Ypos);
line.Size = new Size(myListBox.Width, 20);
line.MouseClick += new MouseEventHandler(line_MouseClick);
myListBox.Controls.Add(line);
// Add and arrange the controls you want in the line
yPos += line.Height;
}
Example for myListBox event handlers - selecting a line:
private void line_MouseClick(object sender, MouseEventArgs)
{
foreach (Control control in myListBox.Controls)
if (control is Panel)
if (control == sender)
control.BackColor = Color.DarkBlue;
else
control.BackColor = Color.Transparent;
}
The code samples above were not tested but the described method was used and found very convenient and simple.

Change button background

After several attempts to change the background of a button, and getting errors of casting and things like that I finnaly got to this point:
Uri dir = new Uri("red_flag.png",UriKind.RelativeOrAbsolute);
ImageSource source = new System.Windows.Media.Imaging.BitmapImage(dir);
ImageBrush bru = new ImageBrush();
bru.ImageSource=source;
bru.Opacity = 100;
This code does not generate errors, but I can't see the changes when I call:
button1.background = bru;
It just makes anything! :(
found the answer myelf after reading Mick's answer, I share with you what I did:
Uri dir = new Uri("red_flag.png", UriKind.Relative);
ImageSource source = new System.Windows.Media.Imaging.BitmapImage(dir);
Image image = new Image();
image.Source = source;
StackPanel stack = new StackPanel();
stack.Children.Add(image);
myButton.Content = stack;
Thanks for your help
Update 1:
For best results set the padding property of your button to 0 (in each of the cases) so the image can resize automatically to fill all the button, please note this could hide your actual content, in my case this was what I wanted.
If this code is part of the click event handler for the same button you will have this problem.
Peter Torr explains why here and offers a solution.
Why can't I change the Background of my Button on a Click event?

Categories