Maybe I am too ignorant to understand this, but I don't know how I can see changes that I am making when I create ControlTemplate, any ControlTemplate. For example, I'm creating TextBox ControlTemplate
<ControlTemplate x:Name="TextBoxTemplate" x:Key="TemplateForTextBox" TargetType="{x:Type TextBox}" >
<Border Background="#215564">
</Border>
</ControlTemplate>
And I have a Button that dynamically creates a TextBox
void Button_Click_1(object sender, RoutedEventArgs e)
{
var window = new Window();
window.Show();
window.Width = 250;
window.Height = 250;
window.Template = FindResource("WindowControlTemplate1") as ControlTemplate;
dynamicTextBox = new TextBox();
Grid.SetRow(dynamicTextBox, 1);
Grid.SetColumn(dynamicTextBox, 0);
this.TextPanel.Children.Add(dynamicTextBox);
dynamicTextBox.IsReadOnly = false;
dynamicTextBox.Text = "";
//Adjusting margin of text box
Thickness margin = dynamicTextBox.Margin;
margin.Top = 30;
dynamicTextBox.Margin = margin;
margin.Left = 10;
dynamicTextBox.Margin = margin;
margin.Bottom = -25;
dynamicTextBox.Margin = margin;
dynamicTextBox.Template = FindResource("TemplateForTextBox") as ControlTemplate;
}
I can not see TextBox until I(user) press the Button, but I wanna see TextBoxes design while I am writing XAML code(in other words until I press Button)
Related
I am trying to build a Revit plugin using WPF and I am trying to add controls to a window dynamically. However, these controls are not getting displayed in the window and there is no error. Any help would be appreciated. Thank you.
Xaml
<ScrollViewer Margin="0,190,-0.4,-1">
<StackPanel Name="TaskList" Height="auto" Width="auto">
</StackPanel>
</ScrollViewer>
c#
for (var i = 0; i < dt.Rows.Count; i++)
{
Canvas canvas = new Canvas();
canvas.Height = 100;
canvas.Width = 300;
canvas.Background = new SolidColorBrush(Colors.Black);
canvas.Margin = new Thickness(20);
System.Windows.Controls.TextBox tb = new System.Windows.Controls.TextBox();
tb.Background = new SolidColorBrush(Colors.Black);
tb.Foreground = new SolidColorBrush(Colors.White);
tb.Width = 300;
tb.FontSize = 30;
tb.Height = 100;
tb.TextWrapping = TextWrapping.Wrap;
tb.MaxLength = 40;
tb.Text = dt.Rows[i][2].ToString();
canvas.Children.Add(tb);
TaskList.Children.Add(canvas);
TaskList.UpdateLayout();
}
EDIT
I am using a page tag as the base not window. Maybe that changes how i should approach the problem?
Remove Canvas entirely. You can add the TextBox elements to the StackPanel (TaskList) directly. If you want a border or spacing then you should use the Border control, not Canvas.
Additionally, only call UpdateLayout() after you've added all the controls to it:
using System.Windows.Controls;
...
for (var i = 0; i < dt.Rows.Count; i++)
{
TextBox tb = new TextBox();
tb.Background = new SolidColorBrush( Colors.Black );
tb.Foreground = new SolidColorBrush( Colors.White );
tb.Width = 300;
tb.FontSize = 30;
tb.Height = 100;
tb.TextWrapping = TextWrapping.Wrap;
tb.MaxLength = 40;
tb.Text = dt.Rows[i][2].ToString();
this.TaskList.Children.Add( tb );
}
this.TaskList.UpdateLayout();
Consider using an ItemsControl, instead of creating UI elements in code behind:
<ScrollViewer>
<ItemsControl x:Name="TaskList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Width="300" Height="100" FontSize="30"
TextWrapping="Wrap" Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Then just add strings to its Items property:
for (var i = 0; i < dt.Rows.Count; i++)
{
TaskList.Items.Add(dt.Rows[i][2].ToString());
}
So I need to add textboxes to a panel with a click of a button. Every click adds one textbox under the last one and so on. But when it goes over the panel height it suddenly makes bigger space between the texboxes even though the int is still the same.
Here's my code so far.
List<TextBox> textboxes = new List<TextBox>();
private void button1_Click(object sender, EventArgs e)
{
tbY += 30;
TextBox tb = new TextBox();
tb.Left = 3;
tb.Top = tbY;
tb.Font = new Font("Verdana", 12, FontStyle.Bold);
tb.Size = new Size(325, 25);
tb.BorderStyle = BorderStyle.None;
button1.Top = tbY;
panel1.Controls.Add(tb);
textboxes.Add(tb);
ScrollToBottom(panel1);
}
The Top of a Control is calculated relative to the scroll position of its Parent.
You are always scrolling to the bottom of your Panel, so you need to set it like this, taking the curent scroll position into account:
tb.Top = tbY + panel1.AutoScrollPosition.Y;
Note that the AutoScrollPosition.Y is negative when you have scrolled downward, so we need to add it!
You might as well use a flowLayoutPanel for this purpose. Use the following properties on your flowLayoutPanel and it'll work as you intend. (without having to do the manual calculation)
List<TextBox> textboxes = new List<TextBox>();
public Form1()
{
InitializeComponent();
flowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
flowLayoutPanel1.WrapContents = false;
flowLayoutPanel1.AutoScroll = true;
}
private void button1_Click(object sender, EventArgs e)
{
TextBox tb = new TextBox();
tb.Left = 3;
tb.Font = new Font("Verdana", 12, FontStyle.Bold);
tb.Size = new Size(325, 25);
tb.Text = tb.Top.ToString();
tb.BorderStyle = BorderStyle.None;
flowLayoutPanel1.Controls.Add(tb);
textboxes.Add(tb);
}
I do not want cut text of textblock. For this reason, I set viewBox.ClipToBounds to false, But it doesn't work.
Please tell me why ClipToBounds=false not work in this code:
private void Btn1_Click(object sender, RoutedEventArgs e)
{
Button button = new Button(); button.Background = Brushes.Red;
button.Width = 70; button.Height = 20;
Canvas.SetLeft(button, 100); Canvas.SetTop(button, 120);
button.Padding = new Thickness(1);
StackPanel stackPanel = new StackPanel();
Viewbox viewBox = new Viewbox();
viewBox.ClipToBounds = false;
Canvas canvas = new Canvas();
canvas.Width = button.Width; canvas.Height = button.Height;
TextBlock textBlock = new TextBlock();
textBlock.Text = "this is a test";
textBlock.FontSize = 15;
textBlock.FontFamily = new FontFamily("Arial");
textBlock.TextWrapping = TextWrapping.NoWrap;
textBlock.Foreground = Brushes.Green;
textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
viewBox.Height = 20;
textBlock.IsHitTestVisible = false;
stackPanel.Children.Add(viewBox);
viewBox.Child = canvas;
canvas.Children.Add(textBlock);
button.Content = stackPanel;
Canvas MainCanvas = new Canvas();
MainCanvas.Children.Add(button);
this.Content = MainCanvas;
}
Screenhsot:
The screenshot below is what I want. :
ClipToBounds is false by default. However, clipping can still happen due to the way certain elements perform layout. Basically the way things work in WPF is that setting ClipToBounds = true will force things to clip. Leaving it set to false means that WPF determines how things should clip based on measure constraints and arrange rects.
If you look at the ArrangeCore and MeasureCore methods in FrameworkElement, you will see that there is quite a bit of logic determining whether something should clip. Of course, things that override FrameworkElement are free to render however they want, but generally they will obey the clipping rules established by the base class.
In the case of a TextBlock, it will definitely clip text that goes outside of its bounds if its size is constrained. You can see this by simply setting a Width on it, or placing it is a parent that has a Width set on it.
If you really need the text to render outside of the bounds of the control, you may have to consider something like writing a custom text rendering element.
Even then, it is still going to be clipped by its parent as soon as you place it in something else that clips. So, you could still end up stuck.
You could try placing the TextBlock on top of the button instead of inside of it, and setting its position to get it in the right place (maybe by binding it to something). This would work, but might get hard to manage if you need to do it too much.
Basically, you are trying to go against one of the hard-coded rules of WPF, so you are likely not going to find an easy way to do it. Perhaps you might want to reevaluate your design and determine if this behavior is really necessary for what you want to do, or if you can go about it in a different way.
Thanks to elgonzo and Xavier.
I realized that I should not put the canvas in the viewbox.
By 2 change my problem solved.
1 - Swap viewbox with canvas.
2 - Remove canvas.with = ...
This is correct code :
private void Btn1_Click(object sender, RoutedEventArgs e)
{
Button button = new Button(); button.Background = Brushes.Red;
button.Width = 70; button.Height = 20;
Canvas.SetLeft(button, 100); Canvas.SetTop(button, 120);
button.Padding = new Thickness(1);
StackPanel stackPanel = new StackPanel();
Viewbox viewBox = new Viewbox();
viewBox.ClipToBounds = false;
Canvas canvas = new Canvas();
// canvas.Width = button.Width; canvas.Height = button.Height;
TextBlock textBlock = new TextBlock();
textBlock.Text = "this is a test";
textBlock.FontSize = 15;
textBlock.FontFamily = new FontFamily("Arial");
textBlock.TextWrapping = TextWrapping.NoWrap;
textBlock.Foreground = Brushes.Green;
textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
viewBox.Height = 20;
textBlock.IsHitTestVisible = false;
stackPanel.Children.Add(canvas);
viewBox.Child = textBlock;
canvas.Children.Add(viewBox);
button.Content = stackPanel;
Canvas MainCanvas = new Canvas();
MainCanvas.Children.Add(button);
this.Content = MainCanvas;
}
I'm developing WP8 app for my own needs and want it to have small live tile with text.
Since small tile cannot display text, I'm generating appropriate image with needed text.
Here is the code:
WriteableBitmap bmpSmall = new WriteableBitmap(159, 159);
var grid = new Grid();
grid.Width = bmpSmall.PixelWidth;
grid.Height = bmpSmall.PixelHeight;
var background = new Canvas();
background.Width = bmpSmall.PixelWidth;
background.Height = bmpSmall.PixelHeight;
SolidColorBrush backColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Text = "qwerty";
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = new SolidColorBrush(Colors.White);
grid.Children.Add(textBlock);
bmpSmall.Render(background, null);
bmpSmall.Render(grid, null);
bmpSmall.Invalidate();
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/smallTile.jpg", System.IO.FileMode.Create, isf))
{
bmpSmall.SaveJpeg(imageStream, 159, 159, 0, 100);
}
}
ShellTile tile = ShellTile.ActiveTiles.First();
FlipTileData tileData = new FlipTileData();
tileData.SmallBackgroundImage = new Uri(#"isostore:/Shared/ShellContent/smallTile.jpg", UriKind.Absolute);
tile.Update(tileData);
And result looks like:
As you see, text is aligned to top left corner. The question is "Why"? Since I'd set textBlock.HorizontalAlignment and textBlock.VerticalAlignment - I expect it in the center of the image.
For example the following XAML looks like you can expect and like I need:
<Grid Width="159" Height="159">
<Grid.Background>
<SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
</Grid.Background>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="28" Foreground="White">qwerty</TextBlock>
</Grid>
What did I miss? How can I center text?
Give the following code a try:
WriteableBitmap bmpSmall = new WriteableBitmap(159, 159);
var grid = new Grid();
grid.Width = bmpSmall.PixelWidth;
grid.Height = bmpSmall.PixelHeight;
var background = new Canvas();
background.Width = bmpSmall.PixelWidth;
background.Height = bmpSmall.PixelHeight;
SolidColorBrush backColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Width = bmpSmall.PixelWidth;
textBlock.Text = "qwerty";
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Stretch;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = new SolidColorBrush(Colors.White);
textBlock.TextAlignment = TextAlignment.Center;
grid.Children.Add(background);
grid.Children.Add(textBlock);
grid.Measure(new Size(bmpSmall.PixelWidth, bmpSmall.PixelHeight));
grid.Arrange(new Rect(0,0,bmpSmall.PixelWidth, bmpSmall.PixelHeight));
grid.UpdateLayout();
bmpSmall.Render(grid, null);
bmpSmall.Invalidate();
I set the TextBlock width to the same as the rest of the tile, and set HorizontalAlignment to stretch, so that control would take up the whole width of the tile. Then I set the TextAlignment property to TextAlignment.Center, in order to center the text. Hope that helps!
Edit: Apparently for writable bitmaps, you must do the measure/arrange/layout steps yourself in order to render controls as you would think they should be rendered. Give this updated code a try, it should work this time!
You will have to set the HorizontalAlignment="Stretch" VerticalAlignment="Stretch" for grid also. Currently grid is only of size of its content i.e textblock.
After copying your code into an empty WPF application, I'm afraid to tell you that your code works just fine:
All I did was to set the Grid.Background to red and the TextBlock.Background to black to clarify the situation:
<Grid Width="159" Height="159">
<Grid.Background>
<SolidColorBrush Color="Red"/>
</Grid.Background>
<TextBlock Background="Black" HorizontalAlignment="Center"
VerticalAlignment="Center" FontWeight="Bold" FontSize="28"
Foreground="White">qwerty</TextBlock>
Therefore, I can only assume that you have a problem elsewhere in your code.
UPDATE >>>
Sorry, you're right, I did misunderstand you. However, after testing your C# code, the story is just the same:
This might look like the same image, but it actually comes from your C# code... I made a couple of little changes, but nothing that affected the position of the TextBlock:
Grid grid = new Grid();
grid.Background = Brushes.Red;
grid.Width = grid.Height = 159.0;
TextBlock textBlock = new TextBlock();
textBlock.Text = "qwerty";
textBlock.Background = Brushes.Black;
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = Brushes.White;
grid.Children.Add(textBlock);
this.Content = grid;
If you put this code into a new WPF project, you'll see that it works just fine, so that only leaves your WriteableBitmap object as the culprit of this problem... what are you using that for? If you're just adding it to your UI, then you can simply add the controls to the Window directly.
From code behind I can set some generic things to my groupbox and stackpanel but I cant find anything on how to highlight a stack panel from code behind.
GroupBox groupbox = new GroupBox();
groupbox.Header = String.Format(node.Element("StudentID").Value);
groupbox.Width = 100;
groupbox.Height = 100;
groupbox.Margin = new Thickness(1);
TextBlock textBlock = new TextBlock();
textBlock.Text = String.Format(node.Element("FirstName").Value + " " + (node.Element("LastName").Value));
textBlock.TextAlignment = TextAlignment.Center;
TextBlock textBlock1 = new TextBlock();
textBlock1.Text = (DateTime.Parse(node.Element("TimeAdded").Value)).ToString("d");
String.Format("{0:d/M/yyyy}", DateTime.Parse(node.Element("TimeAdded").Value));
textBlock1.TextAlignment = TextAlignment.Center;
textBlock1.VerticalAlignment = VerticalAlignment.Bottom;
StackPanel stackPanel = new StackPanel();
stackPanel.Children.Add(groupbox);
stackPanel.Children.Add(textBlock);
stackPanel.Children.Add(textBlock1);
stackPanel.Margin = new Thickness(5);
I wish to on mouse over create a highlight of a ligher grey, also this code belongs to a customcontrol.
Add handlers for the MouseEnter and MouseLeave events:
public MainWindow()
{
InitializeComponent();
StackPanel stackpanel = new StackPanel();
stackpanel.MouseEnter += new MouseEventHandler(stackpanel_MouseEnter);
stackpanel.MouseLeave += new MouseEventHandler(stackpanel_MouseLeave);
}
void stackpanel_MouseLeave(object sender, MouseEventArgs e)
{
StackPanel stackpanel = (StackPanel)sender;
stackpanel.Background = Brushes.Transparent;
}
void stackpanel_MouseEnter(object sender, MouseEventArgs e)
{
StackPanel stackpanel = (StackPanel)sender;
stackpanel.Background = Brushes.LightGray;
}