How can i duplicate and place new stackpanels on buttonpress at runtime? - c#

I have a stack panel in XAML which currently has a column of 7 textboxes. I have a button on my form which i would like to duplicate the current stackpanel and place a new instance of it next to the existing one every time it is clicked.
Is this possible?
My Try:
var mynewstackpanel = new StackPanel();
var entry1 = new TextBox();
var entry2 = new TextBox();
entry1.Name = "newbox1";
entry1.Text= "newboxtext1";
entry2.Name = "newbox2";
entry2.Text = "newboxtext2";
mynewstackpanel.Children.Add(entry1);
mynewstackpanel.Children.Add(entry2);

You want to create the controls dynamically actually. So WPF has got a great support for that.
You can do this using ItemsControl and changing its ItemTemplate to have whatever controls you want to generate. Precisely this is what you want to do:
Take an ItemsControl in the xaml and bind the ItemsSource to an ObservableCollection in the ViewModel.
Change ItemsControl's ItemTemplate to have your StackPanel you are talking about.
Now in button click command, just keep adding data to your ObservableCollection.
This is a rough idea of how you can achieve it. You will have to code yourself.
P.S. Please mark as answered if you feel I answered it.

You can use a ListBox and DataTemplate for this case. You Add items to the ListBox Horizontally using ItemsPanel and define a ItemsPanelTemplate. Refer below code.
<StackPanel>
<ListBox x:Name="items">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel>
<TextBox Width="100" />
<TextBox Width="100" />
<TextBox Width="100" />
<TextBox Width="100" />
<TextBox Width="100" />
<TextBox Width="100" />
<TextBox Width="100" />
</StackPanel>
<StackPanel>
<TextBox Width="35" />
<TextBox Width="35" />
<TextBox Width="35" />
<TextBox Width="35" />
<TextBox Width="35" />
<TextBox Width="35" />
<TextBox Width="35" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<Button Content="Add Content" Click="Button_Click"></Button>
</StackPanel>
public partial class MainWindow : Window
{
ObservableCollection<string> lst;
public MainWindow()
{
InitializeComponent();
lst = new ObservableCollection<string>();
items.ItemsSource = lst;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
lst.Add("");
}
}

Related

TemplateColumn button command binding not working in Syncfusion DataGrid

I'm using Syncfusion's datagrid in a UWP project. Everything works fine except command binding of button inside a GridTemplateColumn. What could be the issue ?
XAML
<my:GridTemplateColumn MappingName="Actions" HeaderText="Actions"
AllowFiltering="False">
<my:GridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Spacing="0" HorizontalAlignment="Center">
<Button VerticalAlignment="Center" Width="40" Content="Delete"
my:FocusManagerHelper.FocusedElement="True"
Command="{x:Bind ViewModel.RemoveBtnCommand}"/>
</StackPanel>
</DataTemplate>
</my:GridTemplateColumn.CellTemplate>
</my:GridTemplateColumn>
View Model
public ICommand RemoveBtnCommand { get; }
public HRMDepartmentsViewModel()
{
IsActive = true;
RemoveBtnCommand = new AsyncRelayCommand(CommandRemoveBtnClickedExecute);
}
private async Task CommandRemoveBtnClickedExecute()
{
// never executed-- code here
}
What else i've tried
I tried to use Binding instead if x:Bind but it also doesn't work
Command="{Binding Path=RemoveBtnCommand}" CommandParameter="{Binding}"
Observation
If i don't use Command and use Click event binding it works.
<my:GridTemplateColumn MappingName="Actions" HeaderText="Actions"
AllowFiltering="False">
<my:GridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Spacing="0" HorizontalAlignment="Center">
<Button VerticalAlignment="Center" Width="40" Content="Delete"
Click="{x:Bind ViewModel.ButtonBase_OnClick}"/>
</StackPanel>
</DataTemplate>
</my:GridTemplateColumn.CellTemplate>
</my:GridTemplateColumn>
View Model
public void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
// It gets called
}
TemplateColumn button command binding not working in Syncfusion DataGrid
I'm afraid you can't bind the button command in the DataTemplate like above, because command will not find correct DataContext. If you want to bind the ViewModel's RemoveBtnCommand, you need get root DataContext then direct to RemoveBtnCommand property. For more please refer the following code.
<Page.DataContext>
<local:MainViewModel x:Name="ViewModel" />
</Page.DataContext>
<Grid>
<Custom:SfDataGrid x:Name="MyDataGrid" ItemsSource="{Binding Orders}">
<Custom:SfDataGrid.Columns>
<Custom:GridTemplateColumn
AllowFiltering="False"
HeaderText="Actions"
MappingName="Actions"
>
<Custom:GridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel
HorizontalAlignment="Center"
Orientation="Horizontal"
Spacing="0"
>
<TextBlock Text="{Binding Name}" />
<Button
Width="40"
VerticalAlignment="Center"
Custom:FocusManagerHelper.FocusedElement="True"
Command="{Binding ElementName=MyDataGrid, Path=DataContext.RemoveBtnCommand}"
Content="Delete"
/>
</StackPanel>
</DataTemplate>
</Custom:GridTemplateColumn.CellTemplate>
</Custom:GridTemplateColumn>
</Custom:SfDataGrid.Columns>
</Custom:SfDataGrid>
</Grid>
You can achieve your requirement by pass the row information as a parameter to the command in ViewModel when clicking a button in TemplateColumn by passing the CommandParameter. Please refer the below KB documentation for more details reference,
KB Link:https://www.syncfusion.com/kb/5910/how-to-pass-row-data-as-parameter-to-the-command-in-viewmodel-when-clicking-the-button-in
Regards,
Vijayarasan S

What is approach to overlap one element above another in XAML when they get/lost focus?

I have two DockPanel elements:
<DockPanel Margin="10">
<TextBlock Text="+ Add new note" />
</DockPanel>
<DockPanel Margin="10">
<ComboBox>
<ComboBoxItem>One</ComboBoxItem>
<ComboBoxItem>Two</ComboBoxItem>
</ComboBox>
<Button Content="Add Note" DockPanel.Dock="Right" Margin="0" Padding="10,0" />
<TextBox Margin="10,0" />
</DockPanel>
I want to get follow result: once I click on first DockPanel, it must be hidden and second one is showed instead. After I click on button Add Note, second DockPanel must be hidden and first one must be appeared again.
I wonder an approach how to make it but don't know where to begin.
I'm appreciate for any suggestions.
A rough solution (no MVVM base) might be the following:
MainWindow.xaml
<Grid>
<DockPanel Margin="10" x:Name="EditDP" Visibility="Collapsed">
<ComboBox>
<ComboBoxItem>One</ComboBoxItem>
<ComboBoxItem>Two</ComboBoxItem>
</ComboBox>
<Button Content="Add Note" DockPanel.Dock="Right" Margin="0" Padding="10,0" Click="ButtonBase_OnClick"/>
<TextBox Margin="10,0" />
</DockPanel>
<DockPanel x:Name="MainDP" Margin="10" MouseLeftButtonDown="UIElement_OnMouseLeftButtonDown">
<TextBlock Text="+ Add new note" />
</DockPanel>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UIElement_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.MainDP.Visibility = Visibility.Collapsed;
this.EditDP.Visibility = Visibility.Visible;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
this.MainDP.Visibility = Visibility.Visible;
this.EditDP.Visibility = Visibility.Collapsed;
}
}
Bind the Visibility property of both the dockpanels to the same boolean and use InverseBooleanToVisibilityConverter / BooleanToVisibilityConverter on each of them.
This way when you flip the boolean using either the click event on the first Dock panel or the button click on the second panel, the two panels will alternatively show up

Radio buttons - showing two diff list with data in the view WPF

I have some code in the view:
<StackPanel Orientation="Horizontal" Background="{StaticResource GrayBrush8}">
<RadioButton Content="Radio1" />
<RadioButton Content="Radio2" />
</StackPanel>
<ct:DynamicFilterPanel Grid.Row="1"
ItemsType="{x:Type db:RadioData1}"
DbContext="{Binding DataContext}"
FilterQuery="{Binding FilterQuery, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ChildCollectionsFilters="{Binding SubTypesFilter}"
WindowType="{x:Type mah:MetroWindow}"
/>
<ct:BDataGrid Grid.Row="2" IsReadOnly="True" ItemsSource="{Binding Model.List}" SelectedItem="{Binding Model.SelectedItem}" />
And I have some class with data and name of columns, models and viewmodels.
When I start the app it shows columns with data of RadioData1. Ok. And the first radiobutton is for that. But how can I do when I click second radio button it shows another list with columns from RadioData2. What kind of converter? Or changes I have to make in this view.
you must edit XAML
<StackPanel Orientation="Horizontal" Background="{StaticResource GrayBrush8}">
<RadioButton Name="Radio1" Content="Radio1" DataContextChanged="RadioButton_DataContextChanged" />
<RadioButton Name="Radio2" Content="Radio2" />
</StackPanel>
and in CS File
add method
private void RadioButton_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (Radio1.IsChecked==true)
{
//your Code
}
else
{
//your other code
}
}
and u can Use visibility for show or hide Something in XAML
<Button Name="btn1" Visibility="Hidden" />
and Use in your CS file like this
if (Radio1.IsChecked==true)
{
btn1.Visibility = Visibility.Visible;
}

How to get the cell content of DatagridTemplateColumn in wpf datagrid?

I have a DataGridTemplateColumn whose header basically consists of StackPanel which contains a Button and TextBlock. I would want to access the Cell content or DataGridCell when the datagridrow is loaded.
My one of the datagridcolumn looks like this:
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate >
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Click="HeaderButtonClick">
<Button.Content>
<Path Stretch="Fill" Fill="Black" Stroke="{x:Null}" StrokeThickness="0.5"
Data="M3.875,0 L5.125,0 5.125,3.875 9,3.875 9,5.125 5.125,5.125 5.125,9 3.875,9 3.875,5.125 0,5.125 0,3.875 3.875,3.875 3.875,0 z" />
</Button.Content>
</Button>
<TextBlock Text="Fund" Margin="20,0,0,0"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Fund}" Margin="20,0,0,0"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
and the datagrid_loadingrow event looks like
var dg = sender as DataGrid;
if (dg != null)
{
foreach (var item in dg.Columns)
{
DataGridCell cell1 = item.GetCellContent(row) as DataGridCell;
}
}
Can anyone help me with this?
This is WPF, not WindowsForms. When using WPF, we data bind to UI control properties, rather than attempting to programmatically set these values. When data binding, you already have access to the data in your code behind/view model, so there really is no need to attempt to access it from the UI controls.
If you look at the DataGridTemplateColumn Class page on MSDN, you'll see this example:
<Grid>
<Grid.Resources>
<!--DataTemplate for Published Date column defined in Grid.Resources. PublishDate is a property on the ItemsSource of type DateTime -->
<DataTemplate x:Key="DateTemplate" >
<StackPanel Width="20" Height="30">
<Border Background="LightBlue" BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding PublishDate, StringFormat={}{0:MMM}}" FontSize="8" HorizontalAlignment="Center" />
</Border>
<Border Background="White" BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding PublishDate, StringFormat={}{0:yyyy}}" FontSize="8" FontWeight="Bold" HorizontalAlignment="Center" />
</Border>
</StackPanel>
</DataTemplate>
<!--DataTemplate for the Published Date column when in edit mode. -->
<DataTemplate x:Key="EditingDateTemplate">
<DatePicker SelectedDate="{Binding PublishDate}" />
</DataTemplate>
</Grid.Resources>
<DataGrid Name="DG1" ItemsSource="{Binding}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<!--Custom column that shows the published date-->
<DataGridTemplateColumn Header="Publish Date" CellTemplate="{StaticResource DateTemplate}" CellEditingTemplate="{StaticResource EditingDateTemplate}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
Notice the Bindings... for example, we can see this:
<DatePicker SelectedDate="{Binding PublishDate}" />
This value can be accessed directly from the PublishDate property of the data bound object, rather than from the DataGrid:
DateTime publishDate = DataBoundCollection.ElementAt(relevantRowIndex).PublishDate;
You can find out more about data binding from the Data Binding Overview page on MSDN.
Here is answer.How you would access template column content using code.If you want to access any type of Control content e.g Button content ,TextBlock content etc.Then you create load event for those Controls.Then go to load event code.In load event you would be access Content of those Controls.
I am going to access the Button child of Stack Panel.
So follow this code.
Xaml:
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate >
<DataTemplate>
<StackPanel Orientation="Horizontal" Loaded="StackPanel_Loaded">
<Button Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Click="HeaderButtonClick">
<Button.Content>
<Path Stretch="Fill" Fill="Black" Stroke="{x:Null}" StrokeThickness="0.5"
Data="M3.875,0 L5.125,0 5.125,3.875 9,3.875 9,5.125 5.125,5.125 5.125,9 3.875,9 3.875,5.125 0,5.125 0,3.875 3.875,3.875 3.875,0 z" />
</Button.Content>
</Button>
<TextBlock Text="Fund" Margin="20,0,0,0"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Fund}" Margin="20,0,0,0"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
Code Behind .cs
private void StackPanel_Loaded(object sender, RoutedEventArgs e)
{
StackPanel stack = sender as StackPanel;
Button button = stack.Children.OfType<Button>().FirstOrDefault();
button.Content = "Change Content";
}
In my situation I want to access button in Template Column.I used this code
XAML
<DataGridTemplateColumn x:Name="deleteDG" Header="Delete" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:Uid="deletetemp" >
<Button Click="deleteBtn_Click" Loaded="Button_Loaded" Width="95" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Background="White" Content="Delete"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Code Behind .cs
private void Button_Loaded(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
button.Content = "Change COntent";
}

Button inside RowDetailsTemplate in DataGrid - how to know which row clicked on?

I have this XAML
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel>
<Button Content="Reply" Name="btnReply" Click="btnReply_Click" HorizontalAlignment="Left" Margin="5" Padding="10,0" />
<Label Content="{Binding Path=Subject}" FontWeight="Bold" />
<Label Content="{Binding Path=Body}" />
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
DataGrid bound to List
inside btnReply_Click I'd like to get instance of MyObject
How do I do this?
var myObject = (sender as FrameworkElement).DataContext as MyObject;
Since the DataContext is inherited.

Categories

Resources