WPF - duplicating a stackpanel - c#

i have this (a rough e.g):
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label .../>
<TextBox .../>
<Button Content="Add new input row" ... />
</StackPanel>
</StackPanel>
pretty self explanatory, i want to add a new Horizontal StackPanel with every click on the button..
is that possible?
thank you!

For this XAML above I will do like this:
In the click event handle of every button name "Add new input row", I mean you can use this event for all of buttons.
private void btn_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
StackPanel stkButtonParent = btn.Parent as StackPanel;
StackPanel stkCover = stkButtonParent.Parent as StackPanel;
StackPanel newRow = NewRow();
stkCover.Children.Add(newRow);
}
private StackPanel NewRow() {
StackPanel stk = new StackPanel();
stk.Orientation = Orientation.Horizontal;
Label lbl = new Label();
lbl.Foreground = Brushes.Red; // some attribute
TextBox txt = new TextBox();
txt.Background = Brushes.Transparent; // some attribute
Button btn = new Button();
btn.Content = "Add new row";
btn.Click += btn_Click;
stk.Children.Add(lbl);
stk.Children.Add(txt);
stk.Children.Add(btn);
return stk;
}

Yes it is possible try handling the event like this for example:
// Create your StackPanel.
StackPanel sp = new StackPanel();
sp.Orientation = Orientation.Horizontal;
// Add controls to new StackPanel
// Control con = new Control();
// sp.Children.Add(con);
// Add created control to a previously created (and named) container.
myStackPanel.Children.Add(sp);
If you would like your StackPanel to contain some controls you can also add them to it here.
There is a way to do this via XamlReader as well, but I have never tried it.
Here is a link to a short article:
arcanecode.com

Related

Select ListBoxItem under RightTapped event

I have the following event right now
private void contactGrid_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
if (contactGrid.SelectedIndex >= 0)
{
FrameworkElement senderElement = sender as FrameworkElement;
MenuFlyout menu = new MenuFlyout();
MenuFlyoutItem item1 = new MenuFlyoutItem() { Text = "Edit Contact" };
MenuFlyoutItem item2 = new MenuFlyoutItem() { Text = "Comfirm" };
MenuFlyoutSubItem item2a = new MenuFlyoutSubItem() { Text = "Remove Contact" };
item1.Click += new RoutedEventHandler(EditContactClicked);
item2.Click += new RoutedEventHandler(RemoveContactClicked);
item2a.Items.Add(item2);
menu.Items.Add(item1);
menu.Items.Add(item2a);
menu.ShowAt(senderElement, e.GetPosition(contactGrid));
}
}
This works fine and creates the right click context menu at the mouse pointer on top of a listbox item, but only if it has been selected first. What I can't figure out is how to get the RightTapped event to select the item that was right tapped. I have yet to test this in tablet mode and
I'm currently using a mouse to trigger the right tapped event (by right clicking).
Is the default behaviour of a long press (to trigger a right tap) in tablet mode such that it selects the item anyway?
As far as I understand, contactGrid is your ListBox? I guess you have any kind of List or Collection set as the ItemsSource of the ListBox? Then you can set the SelectedItem property in your right tapped-event like following:
First you need to modify the ItemTemplate, so that RightTapped belongs to a ListBoxItem:
<ListBox x:Name="ContactGrid">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="Transparent" RightTapped="contactGridItem_RightTapped">
<TextBlock Text="{Binding}" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And in code (I'm actually wondering that the Flyout is shown above the selectedItem and not above the whole ListBox):
private void contactGridItem_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
FrameworkElement senderElement = sender as FrameworkElement;
// Now you can get the tapped Item from the DataContext and set is as selected
contactGrid.SelectedItem = senderElement.DataContext;
if (contactGrid.SelectedIndex >= 0)
{
MenuFlyout menu = new MenuFlyout();
MenuFlyoutItem item1 = new MenuFlyoutItem() { Text = "Edit Contact" };
MenuFlyoutItem item2 = new MenuFlyoutItem() { Text = "Comfirm" };
MenuFlyoutSubItem item2a = new MenuFlyoutSubItem() { Text = "Remove Contact" };
item1.Click += new RoutedEventHandler(EditContactClicked);
item2.Click += new RoutedEventHandler(RemoveContactClicked);
item2a.Items.Add(item2);
menu.Items.Add(item1);
menu.Items.Add(item2a);
menu.ShowAt(senderElement, e.GetPosition(contactGrid));
}
}
(not tested, but that's how I would solve it)

C# WPF Can't click button after defining margin

I have created a button in my WPF Application using the following code:
Button EditButton = new Button();
EditButton.Margin = new System.Windows.Thickness(Location[0], Location[1], 0, 0);
EditButton.Height = double.Parse("20");
EditButton.Width = double.Parse("20");
EditButton.Cursor = System.Windows.Input.Cursors.Hand;
EditButton.Content = "TEST!";
EditButton.Click += new System.Windows.RoutedEventHandler(Edit_Click);
Grid.Children.Add(EditButton);
Location[1] += 17;
The button works perfectly when I have not defined EditButton.Margin but as soon as I define it I can't click it and the cursor does not change. I have searched the internet around for an answer and none of them seemed to work. Thanks in advance.
If you cannot click the control you have created, then it is generally being caused by other control being on top of it.
I would suggest altering your code slightly and move on from that point:
var stackPanel = new StackPanel();
var button = new Button();
button.Content = "Your Button";
button.Click += new System.Windows.RoutedEventHandler(Edit_Click);
stackpanel.Children.Add(button);
I suggest using StackPanel as it automatically arrange your control and thus prevents it from overlapping you can start from this point on see whether issue was caused by grid or some other component.
Button will stretch by default to its content, so will StackPanel.
Not sure what 'Location' is in your code, and I assume 'Grid' is the name of the grid. The below works.
public MainWindow()
{
InitializeComponent();
Button EditButton = new Button();
EditButton.Margin = new System.Windows.Thickness(10, 10, 0, 0);
EditButton.Height = double.Parse("20");
EditButton.Width = double.Parse("20");
EditButton.Cursor = System.Windows.Input.Cursors.Hand;
EditButton.Content = "TEST!";
EditButton.Click += new System.Windows.RoutedEventHandler(Edit_Click);
Grid.Children.Add(EditButton);
// Location[1] += 17;
}
private void Edit_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
XAML -
<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="Grid">
</Grid>
</Window>
It looks like you want to do this programmatically, but if you define it in XAML, you could set the button's Panel.ZIndex property to some high number to bring it to the front:
<Button Content="TEST!" Panel.ZIndex="1000" Height="20" Width="20" Cursor="Hand" Click="Edit_Click" />
Hope that helps somebody...

Add StackPanel and more than one TextBlock inside Button

I want to add a number of TextBlocks inside a Button. How can I add a number of them, along with StackPanels or Canvases, in C#, as shown below in XAMAL
<Button>
<StackPanel>
<TextBlock Text="ABC"/>
<TextBlock Text="DEF"/>
</StackPanel>
</Button>
It's easy:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
var tb1 = new TextBlock() { Text = "TextBlock 1" };
var tb2 = new TextBlock() { Text = "TextBlock 2" };
var stackPanel = new StackPanel();
stackPanel.Children.Add(tb1);
stackPanel.Children.Add(tb2);
var button = new Button() { Content = stackPanel };
this.Content = button;
}
}
Maybe you should think about an enclosing control of csharpfolk's answer. This would help to get a reuseable control.
The text strings are good to use as a dependency property. :)
Regards,
- Tobbo

Create textblock with textrun object at runtime

iam trying to create a TextBlock with runobject at runtime.
i need the textblock to show following text:
Please Click Here to go to next Page.
Click here should be a "link" like, where the user can click on it and he will move to the next tabitem ..
i have:
var tbGoToNextTab = new TextBlock
{
Content = "Please Click Here to go to next Page.",
Foreground = new SolidColorBrush(Colors.Black)
};
tbGoToNextTab .Click +=new RoutedEventHandler(tbGoToNextTab_Click);
how would i just make the Click Here Clickable, have underline and blue text color and perform an action when clicking on it ?
thanks in advance
EDIT:
I just want the 2 Words "Click Here" clickable ...the rest should be displayed as normal text..
I think i should be doing this with Inlines.. any suggestions ?
Something like this? (untested)
var hyperlink = new HyperLink(new Run("Click Here"));
hyperlink.Click += new RoutedEventHandler(tbGoToNextTab_Click);
var span = new Span();
span.Inlines.Add(new Run("Please "));
span.Inlines.Add(hyperlink);
span.Inlines.Add(new Run(" to go to next Page"));
var tbGoToNextTab = new TextBlock
{
Content = span,
Foreground = new SolidColorBrush(Colors.Black)
};
Ok found the Answer ...
As i supposed i had to use the Inline property ..
i found the answer in this post:
Add hyperlink to textblock wpf From Stanislav Kniazev
Thanks all...
To manage a left click action, add a handler on the PreviewMouseLeftButtonDown
tbGoToNextTab.PreviewMouseLeftButtonDown += OntbGoToNextTabPreviewMouseLeftButtonDown;
void OntbGoToNextTabPreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// write code here...
}
To manage underline and color change, write a Style in xaml, in this Style put a Trigger that will change your TextBlock on the IsMouseOver property change.
<Window.Resources>
<Style x:Key="HyperLinkStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextDecorations" Value="Underline" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
tbGoToNextTab.Style = FindResource("HyperLinkStyle") as Style;
You will have to declare a TextBlock specifically for the clickable text and other TextBlocks for the static text.
Have something like this..
Textblock as content in the button..so that its clickable.
Canvas pnel = new Canvas();
var btntab = new Button();
var tbGoToNextTab1 = new TextBlock();
var tbGoToNextTab2 = new TextBlock();
var tbGoToNextTab3 = new TextBlock();
tbGoToNextTab1.Text = "Please ";
tbGoToNextTab2.Text = "Click Here";
tbGoToNextTab3.Text = " to go to next Page.";
tbGoToNextTab1.Margin = new Thickness(0, 0, 0, 0);
btntab.Margin = new Thickness(40, 0, 0, 0);
tbGoToNextTab3.Margin = new Thickness(95, 0, 0, 0);
tbGoToNextTab1.Foreground = new SolidColorBrush(Colors.Black);
tbGoToNextTab2.Foreground = new SolidColorBrush(Colors.Black);
tbGoToNextTab3.Foreground = new SolidColorBrush(Colors.Black);
btntab.Click += new RoutedEventHandler(btntab_Click);
btntab.Content = tbGoToNextTab2;
pnel.Children.Add(tbGoToNextTab1);
pnel.Children.Add(btntab);
pnel.Children.Add(tbGoToNextTab3);
Text112.Children.Add(pnel);
If you handle Click event for the TextBlock, it will process click anywhere within the boundary of the control.
If you need only part of the text clickable, you should place a Hyperlink within the body of your TextBlock. By the way, it has an extra benefit of highlighting the clickable area so that your was not confused with the text that says, "Click Here" which is not clickable.
Here's relevant WPF snippet:
<TextBlock>
<Run>Please</Run>
<Hyperlink>
<Run Text="Click Here"/>
</Hyperlink>
<Run>to go to next Page.</Run>
</TextBlock>

How to add a StackPanel in a Button in C# code behind

How to add a StackPanel in a Button using c# code behind (i.e. convert the following XAML to C# )? There is no Button.Children.Add...
<Button>
<StackPanel Orientation="Horizontal" Margin="10">
<Image Source="foo.png"/>
</StackPanel>
</Button>
Image img = new Image();
img.Source = new BitmapImage(new Uri("foo.png"));
StackPanel stackPnl = new StackPanel();
stackPnl.Orientation = Orientation.Horizontal;
stackPnl.Margin = new Thickness(10);
stackPnl.Children.Add(img);
Button btn = new Button();
btn.Content = stackPnl;
Set Button.Content instead of using Button.Children.Add
As a longer explanation:
Button is a control which "only has 1 child" - its Content.
Only very few controls (generally "Panels") can contain a list of zero or more Children - e.g. StackPanel, Grid, WrapPanel, Canvas, etc.
As your code already shows, you can set the Content of a Button to be a Panel - this would ehn allow you to then add multiple child controls. However, really in your example, then there is no need to have the StackPanel as well as the Image. It seems like your StackPanel is only adding Padding - and you could add the Padding to the Image rather than to the StackPanel if you wanted to.
Use like this
<Window.Resources>
<ImageSource x:Key="LeftMenuBackgroundImage">index.jpg</ImageSource>
<ImageBrush x:Key="LeftMenuBackgroundImageBrush"
ImageSource="{DynamicResource LeftMenuBackgroundImage}"/>
</Window.Resources>
and in Codebehind
Button btn = new Button();
btn.HorizontalContentAlignment = HorizontalAlignment.Stretch;
btn.VerticalContentAlignment = VerticalAlignment.Stretch;
StackPanel stk = new StackPanel();
stk.Orientation = Orientation.Horizontal;
stk.Margin = new Thickness(10, 10, 10, 10);
stk.SetResourceReference(StackPanel.BackgroundProperty, "LeftMenuBackgroundImageBrush");
btn.Content = stk;
In Xaml :
<Button x:Name="Btn" Click="Btn_Click" Orientation="Horizontal" Margin="10">
<StackPanel>
<Image Source="foo.png" Height="16" Width="16"/>
</StackPanel>
</Button>
In C# :
Button btn = new Button();
StackPanel panel = new StackPanel();
Image img = new Image
{
Source = "../foo.png"
}
panel.Children.Add(img);
btn.Content = panel;
I advise you to put the image in xaml resources :
<Window.Resources>
<BitmapImage x:Key="Img" UriSource="/Img/foo.png"/>
</Window.Resources>
And call it like this :
Image img = new Image
{
Source = (BitmapImage)FindResource("Img")
};

Categories