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());
}
Related
lets say i have 10 rows in my database table. I want to create 10 Buttons and TextBlock inside Buttons filled with data rows. I already create the 10 Buttons and TextBlock inside it here is the code
for (int i = 0; i < 10; i++)
{
Button Btn = new Button();
Style style = this.FindResource("MetroNewButton") as Style;
Btn.Style = style;
Btn.Width = 250;
Btn.Height = 80;
Btn.Name = "BtnCA" + i;
Btn.FlowDirection = FlowDirection.LeftToRight;
Btn.HorizontalAlignment = HorizontalAlignment.Left;
Btn.VerticalAlignment = VerticalAlignment.Top;
for (int j = 0; j < 10; j++)
{
Grid GridContent = new Grid();
GridContent.Width = 250;
GridContent.Height = 80;
TextBlock txtBlock = new TextBlock();
txtBlock.Name = "txtBlock" + j;
txtBlock.TextWrapping = TextWrapping.Wrap;
txtBlock.FontSize = 14;
txtBlock.FontWeight = FontWeights.Bold;
//txtBlock1.FlowDirection = FlowDirection.RightToLeft;
txtBlock.Padding = new Thickness(10, 20, 0, 0);
txtBlock.VerticalAlignment = VerticalAlignment.Top;
Grid.SetRow(txtBlock, 0);
GridContent.Children.Add(txtBlock);
Btn.Content = GridContent;
}
}
Okay and i have list carries data from database.I want to distribute data to text block, So how to put data in Text block ?
I think, using ItemsControl with proper ItemTemplate would be better idea than creating all the controls in for loop. Just create a list of objects representing your data, bind it to ItemsCOntrol(ItemsSource={Binding your_path}), and set proper item template for grid. After that, put an ItemsControl inside a button. If i understood you right, that should solve your problem.
Instead of using this for loop, you can create buttons using XAML and MVVM binding.
<DataGrid ItemsSource="{Binding btnList}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="{Binding btn_NAME}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Then fetch content from db and fill it into btnList.
To get more idea about MVVM binding, please go through this and this.
Here is my code:
Grid gameboard = new Grid();
gameboard.HorizontalAlignment = HorizontalAlignment.Left;
gameboard.VerticalAlignment = VerticalAlignment.Top;
gameboard.Width = Window.Current.Bounds.Width;
gameboard.Height = Window.Current.Bounds.Width;
Border border = new Border();
border.BorderThickness = new Thickness(1);
border.BorderBrush = new SolidColorBrush(Colors.Blue);
for (int j=0;j<7;j++)
{
gameboard.ColumnDefinitions.Add(new ColumnDefinition());
}
for (int i = 0; i < 7; i++)
{
gameboard.RowDefinitions.Add(new RowDefinition());
}
I am a learner, now i want to show my grid lines, can someone help me?
thanks a lot!
Since you are learning, I will help kick start your efforts with something to get you and others in a similar situation to the next step.
Start with code like the following, and tweak it, learn it, research it, and most of all have fun.
XAML
<Grid Name="LayoutRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="30" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Grid>
CODE
public MainPage()
{
this.InitializeComponent();
DataContext = this;
Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Grid gameboard = new Grid();
gameboard.HorizontalAlignment = HorizontalAlignment.Stretch;
gameboard.VerticalAlignment = VerticalAlignment.Stretch;
for (int j = 0; j < 7; j++)
{
var cd = new ColumnDefinition();
cd.Width = new GridLength(1, GridUnitType.Star);
var rd = new RowDefinition();
rd.Height = new GridLength(1, GridUnitType.Star);
gameboard.ColumnDefinitions.Add(cd);
gameboard.RowDefinitions.Add(rd);
}
for (int j = 0; j < 7; j++)
{
for (int i = 0; i < 7; i++)
{
Border border = new Border();
border.BorderThickness = new Thickness(1);
border.BorderBrush = new SolidColorBrush(Colors.Blue);
border.HorizontalAlignment = HorizontalAlignment.Stretch;
border.VerticalAlignment = VerticalAlignment.Stretch;
var tb = new TextBlock();
tb.Text = string.Format($"i={i}; j={j}");
tb.Margin = new Thickness(4);
Grid.SetColumn(border, j);
Grid.SetRow(border, i);
border.Child = tb;
gameboard.Children.Add(border);
}
}
LayoutRoot.Children.Add(gameboard);
}
RESULT
SUMMARY
It's a start. It's not perfect, and to get the inner borders to not be thicker than the edges will take a small amount of effort, but should not be too difficult. Hint: think about how to use border.BorderThickness = new Thickness(l, t, r, b); where l/t/r/b are 1 or 0 depending on i/j. I might even make this an interview question; could be a fun discussion.
You can use Grid.ShowGridLines Property and add grid lines.
gameboard.ShowGridLines = true;
I have a window with that structure:
Then in the code behind of the window in the constructor I add the following code:
int numRow = 2;
int numColumn = 3;
for (int row = 0; row < numRow; row++)
{
var rd = new RowDefinition();
rd.Height = new GridLength(1.0, GridUnitType.Star);
grdMain.RowDefinitions.Add(rd);
}
for (int column = 0; column < numColumn; column++)
{
var cd = new ColumnDefinition();
cd.Width = new GridLength(1.0, GridUnitType.Star);
grdMain.ColumnDefinitions.Add(cd);
}
for (int row = 0; row < numRow; row++)
{
for (int column = 0; column < numColumn; column++)
{
//var borderImage = new Border();
//borderImage.BorderThickness = new Thickness(1);
//borderImage.BorderBrush = new SolidColorBrush(Colors.Red);
var finalImage = new Image();
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/EasyRun;component/Resources/Images/ITA.png");
logo.EndInit();
finalImage.Source = logo;
//borderImage.Child = finalImage;
Grid.SetRow(finalImage, row);
Grid.SetColumn(finalImage, column);
grdMain.Children.Add(finalImage);
}
by doing so I expect the window to resize rows and columns accordin to the size of the parent window. But what happens is that while the horizontal stretch works the vertical doesn't.
So in short what I'd like is the grid to stretch columns/rows according to its parent window size
Try using a dockpanel instead then a stack panel
<DockPanel Name="stpMain">
<Button DockPanel.Dock="Bottom" Content="AAA" Width="100" Click="Button_Click"></Button>
<Border BorderThickness="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0" BorderBrush="Red">
<Grid Name="grdMain"></Grid>
</Border>
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.
I have canvas A and canvas B.
Canvas A contains an Image and a grid with diffrent colour squares.
numSelectCan is a diffrent image.
Once i click on a square a event triggers that should set the visibilty state of numSelectCan to visible and then it should show up overlaping Canvas A.
That is not the case. I have tryed everything but i cant get numSelectCan to show up at all.
During development numSelectCan is displayed and works fine. At runtime numSelectCan is just gone. I tryed disabling A but still no success.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="10,0,10,10">
<Controls:RoundButton x:Name="btnCancel" PressedBrush="Orange" Foreground="White" BorderBrush="White" ImageSource="/Assets/Appgraphics/Buttons/cancel.png" HorizontalAlignment="Left" VerticalAlignment="Bottom" Click="btnCancel_Click"/>
<Controls:RoundButton x:Name="btnQuestion" PressedBrush="Orange" Foreground="White" ImageSource="/Assets/Appgraphics/Buttons/questionmark.png" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,10,0,0" Click="btnQuestion_Click" BorderBrush="White"/>
<Controls:RoundButton x:Name="btnConfirm" PressedBrush="Orange" Foreground="White" BorderBrush="White" ImageSource="/Assets/Appgraphics/Buttons/check.png" HorizontalAlignment="Right" VerticalAlignment="Bottom" Click="confirmSelection"/>
<Canvas x:Name="picCanvas" HorizontalAlignment="Center" Width="582" Height="320">
<Image x:Name="imgBackCC" Height="320" Width="582" Stretch="Fill" HorizontalAlignment="Center" Source="" Margin="0,0,0,0"/>
</Canvas>
<Canvas x:Name="numSelectCan" HorizontalAlignment="Center" Height="155" Visibility="Visible" Width="530" VerticalAlignment="Center">
<Image x:Name="numSelBackground" Source="/Assets/Appgraphics/UserInterface/numFieldBackground.png" Height="155" Width="530" Stretch="Fill"/>
<Image x:Name="numFieldButton1" Source="/Assets/Appgraphics/UserInterface/numField0.png" Width="70" Height="70" Canvas.Left="5" Canvas.Top="5"/>
<Image x:Name="numFieldButton2" Source="/Assets/Appgraphics/UserInterface/numField1.png" Width="70" Height="70" Canvas.Left="80" Canvas.Top="5"/>
<Image x:Name="numFieldButton3" Source="/Assets/Appgraphics/UserInterface/numField2.png" Width="70" Height="70" Canvas.Left="155" Canvas.Top="5"/>
<Image x:Name="numFieldButton4" Source="/Assets/Appgraphics/UserInterface/numField3.png" Width="70" Height="70" Canvas.Left="230" Canvas.Top="5"/>
<Image x:Name="numFieldButton5" Source="/Assets/Appgraphics/UserInterface/numField4.png" Width="70" Height="70" Canvas.Left="305" Canvas.Top="5"/>
<Image x:Name="numFieldButton6" Source="/Assets/Appgraphics/UserInterface/numField5.png" Width="70" Height="70" Canvas.Top="80" Canvas.Left="5"/>
<Image x:Name="numFieldButton7" Source="/Assets/Appgraphics/UserInterface/numField6.png" Width="70" Height="70" Canvas.Left="80" Canvas.Top="80"/>
<Image x:Name="numFieldButton8" Source="/Assets/Appgraphics/UserInterface/numField7.png" Width="70" Height="70" Canvas.Left="155" Canvas.Top="80"/>
<Image x:Name="numFieldButton9" Source="/Assets/Appgraphics/UserInterface/numField8.png" Width="70" Height="70" Canvas.Left="230" Canvas.Top="80"/>
<Image x:Name="numFieldButton10" Source="/Assets/Appgraphics/UserInterface/numField9.png" Width="70" Height="70" Canvas.Left="305" Canvas.Top="80"/>
<Image x:Name="numFieldDelButton" Source="/Assets/appgraphics/UserInterface/numFieldDelete.png" Width="145" Height="145" Canvas.Top="5" Canvas.Left="380" />
</Canvas>
</Grid>
</Grid>
Not sure what is going wrong here, or if im missing a simple thing like setting the display order for the diffrent canvases
Any Ideas/Advice is appreciated.
Update
I added the entire content panel from my xaml.
heres the function that creates the grid for me when the page is initialized
public void createGrid()
{
//create the grid
Grid backGrid = new Grid();
backGrid.Width = 530;
backGrid.Height = 285;
backGrid.HorizontalAlignment = HorizontalAlignment.Center;
backGrid.VerticalAlignment = VerticalAlignment.Center;
backGrid.ShowGridLines = false;
backGrid.Margin = new Thickness(25, 15, 0, 0);
//define columns
for (int c = 0; c < 10; c++)
{
ColumnDefinition colDef = new ColumnDefinition();
backGrid.ColumnDefinitions.Add(colDef);
}
//define rows
for (int r = 0; r < 6; r++)
{
RowDefinition rowDef = new RowDefinition();
backGrid.RowDefinitions.Add(rowDef);
}
//colour counter
int counter = 0;
//create textboxes
for (int r = 0; r < 6; r++)
{
for (int c = 0; c < 10; c++)
{
//set the coulour of the canvases based on the counter
if (counter == 4)
{
counter = 0;
}
SolidColorBrush tempBrush = new SolidColorBrush();
switch (counter)
{
case 0:
tempBrush = new SolidColorBrush(Colors.Red);
break;
case 1:
tempBrush = new SolidColorBrush(Colors.Orange);
break;
case 2:
tempBrush = new SolidColorBrush(Colors.Blue);
break;
case 3:
tempBrush = new SolidColorBrush(Colors.Green);
break;
}
string canName = c.ToString() + r.ToString();
string txtName = "text" + c.ToString() + r.ToString();
string tempCanName = "canvas" + c.ToString() + r.ToString();
//creating the canvas
Canvas tempCanvas = new Canvas();
tempCanvas.Name = tempCanName;
tempCanvas.Background = tempBrush;
tempCanvas.HorizontalAlignment = HorizontalAlignment.Stretch;
tempCanvas.VerticalAlignment = VerticalAlignment.Stretch;
tempCanvas.Margin = new Thickness(2);
//creating the textblock
TextBlock tempName = new TextBlock();
tempName.Width = 32;
tempName.Height = 32;
tempName.Name = txtName;
tempName.Foreground = new SolidColorBrush(Colors.White);
tempName.TextAlignment = TextAlignment.Center;
tempName.Margin = new Thickness(13, 0, 0, 0);
tempName.FontWeight = FontWeights.Bold;
tempName.HorizontalAlignment = HorizontalAlignment.Center;
tempName.VerticalAlignment = VerticalAlignment.Center;
tempName.Visibility = Visibility.Visible;
tempName.FontSize = 30;
tempName.Tap += tempName_Tap;
//adding the canvas to the grid
Grid.SetRow(tempCanvas, r);
Grid.SetColumn(tempCanvas, c);
//adding all items into the canvas and into the grid
tempCanvas.Children.Add(tempName);
backGrid.Children.Add(tempCanvas);
//increment counter
counter++;
}
}
//add the grid into the mainpage
picCanvas.Children.Add(backGrid);
}
All of this works. I get the grid with all the diffrent colour squares, but when I press textblock, I want my 2nd canvas to pop up and that does not happen. I added breakpoints through out and it goes through all of them, i just dont see the second canvas
heres the code for capturing the tap on the textblock
//function that handels the event when a textblock is tapped
private void tempName_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
//create a copy of the object that triggerd this event
TextBlock tempBlock = sender as TextBlock;
//create a string from the name of this textblock and then cut of the textpart from the name
string tempName = tempBlock.Name;
tempName = tempName.Substring(4);
//move the canvas top or bottom based on which row the current selection is in
string currentRow = tempName.Substring(1);
if ((currentRow == "0") || (currentRow == "1") || (currentRow == "2"))
{
numSelectCan.VerticalAlignment = VerticalAlignment.Top;
}
else
{
numSelectCan.VerticalAlignment = VerticalAlignment.Bottom;
}
//show the number selector control
numSelectCan.Visibility = Visibility.Visible;
}
I am still stuck on this. Cant get numSelectCan to show up...
hello I have tried your code and what i found is that your question is little bit confusing so i assume that you want your second canvas to be visible on tap on the textblock. but you have not register any event-handler on tap on textblock so no event fired that's why first make your textblock visible and add a tap event handler on which you can set the visibility of second canvas.
also tempName_Tap eventHandler is you color gridbox eventhandler not a textblock tap eventhandler so it never register you tap on text block.
Also in the beginning you write that you want your second canvas to be visible on tap on the grid box for that your code is working fine.
I took your xaml/code and tested it out with my own images. Without the images (or entire project) to see how they are drawing on the canvas, I have to say there is a chance that you don't have the correct Z-Index for your 2 canvases. They normally are layered one on top of the other not shifted off to one side. You can set which Canvas is on top of the other by setting the SetZIndex. Try calling:
//show the number selector control
numSelectCan.Visibility = Visibility.Visible;
Canvas.SetZIndex(numSelectCan, 5);
and to hide it again:
//Hide the number selector control
numSelectCan.Visibility = Visibility.Hidden;
Canvas.SetZIndex(numSelectCan, -5);
Of course the Hidden and changing the ZIndex order might be a little redundant. But I have had trouble with one of the canvases taking the events instead of the one that is displayed so I do both.