UWP/XAML: Drawing and moving listbox items on canvas - c#

I want to draw listbox items on a Canvas, place them somewhere, and then move them around, finding inspiration in the following very good example Brewer Floating Content. However I don't want to duplicate this specific example from the blog.
Hence I attempt to draw items on listbox with a Canvas, but fail again, though in WPF this works easily.
The XAML code is:
<UserControl.Resources>
<DataTemplate x:Key="ThingTemplate" x:DataType="local:Thing">
<Border Width="150" BorderBrush="#FF9B3333" BorderThickness="2"
ManipulationMode="TranslateX, TranslateY, TranslateInertia"
ManipulationDelta="Border_ManipulationDelta">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Border Background="#FF9B3333" Grid.Row="1">
<TextBlock Text="{Binding Comment}" HorizontalAlignment="Center"
VerticalAlignment="Center" TextWrapping="WrapWholeWords" Foreground="Black" Padding="4" />
</Border>
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListBox x:Name="ThingCanvas" Grid.Row="1" ItemTemplate="{StaticResource ThingTemplate}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
and the source code-behind:
public sealed partial class UserControl1 : UserControl
{
public UserControl1()
{
this.InitializeComponent();
for (var i = 0; i < 4; i++)
{
var newThing = new Thing() { Comment = "Item" + i.ToString() };
ThingCanvas.Items.Add(newThing);
}
}
private void Border_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
var left = Canvas.GetLeft(this) + e.Delta.Translation.X;
var top = Canvas.GetTop(this) + e.Delta.Translation.Y;
Canvas.SetLeft(this, left);
Canvas.SetTop(this, top);
}
}
public class Thing
{
public string ImagePath { get; set; }
public string Comment { get; set; }
}
Strange is that the Canvas cannot access to IsItemsHost property, which is set in WPF.
Also hindering is that style setters cannot be databound in UWP, so that Canvas.Left and Canvas.Top cannot be bound.
Thank you for helping me advance on this topic.
RudiAcitivity

Related

How to get a scrollviewer's scrollable height to update in an interaction request

EDIT: I discovered that it was in fact the items presenter in my items control within the scroll viewer that wasn't updating correctly rather than the scrollviewer. I added an answer to reflect this.
I have a simple set up for a custom view interaction request. The view contains a scroll viewer but the scroll viewers scrollable height doesn't update if the items control within it has an items source update. The relevant code is below.
Confirmation model:
public class ProfileImportConfirmation : Confirmation
{
public ObservableCollection<ProfileAcceptPair> PossibleProfiles { get; set; } = new ObservableCollection<ProfileAcceptPair>();
public ObservableCollection<Profile> ConfirmedProfiles { get; set; } = new ObservableCollection<Profile>();
}
ViewModel:
public class ProfileImportPopupViewModel : BindableBase, IInteractionRequestAware
{
ProfileImportConfirmation _profileImportConfirmation;
public InteractionRequest<Confirmation> YesNoConfirmationInteractionRequest { get; }
public DelegateCommand AcceptCommand { get; set; }
public DelegateCommand CancelCommand { get; set; }
public ProfileImportPopupViewModel()
{
AcceptCommand = new DelegateCommand(Accept);
CancelCommand = new DelegateCommand(Cancel);
YesNoConfirmationInteractionRequest = new InteractionRequest<Confirmation>();
}
public INotification Notification
{
get { return _profileImportConfirmation; }
set
{
if (value is ProfileImportConfirmation confirmation)
{
_profileImportConfirmation = confirmation;
OnPropertyChanged(nameof(Notification));
}
}
}
public Action FinishInteraction { get; set; }
void Cancel()
{
_profileImportConfirmation.Confirmed = false;
FinishInteraction();
}
void Accept()
{
_profileImportConfirmation.Confirmed = true;
_profileImportConfirmation.ConfirmedProfiles.Clear();
_profileImportConfirmation.ConfirmedProfiles.AddRange(_profileImportConfirmation.PossibleProfiles.Where(p => p.Accepted).Select(p => p.Profile).ToList());
if (_profileImportConfirmation.ConfirmedProfiles.Any(p => p.IsRootProfile))
YesNoConfirmationInteractionRequest.Raise(
new Confirmation
{
Title = DisplayStrings.AreYouSureLabel,
Content = "Proceed?"
},
confirmed => FinishInteraction());
else
{
FinishInteraction();
}
}
}
View:
<UserControl
MaxHeight="500"
MinWidth="400"
d:DataContext="{d:DesignInstance Type=viewModels:ProfileImportPopupViewModel, IsDesignTimeCreatable=False}"
Loaded="ProfileImportPopup_OnLoaded">
<i:Interaction.Triggers>
<mvvm:InteractionRequestTrigger SourceObject="{Binding YesNoConfirmationInteractionRequest, Mode=OneWay}">
<mvvm:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource PopupWindow}" WindowStartupLocation="CenterOwner">
<mvvm:PopupWindowAction.WindowContent>
<popups:YesNoConfirmationPopup />
</mvvm:PopupWindowAction.WindowContent>
</mvvm:PopupWindowAction>
</mvvm:InteractionRequestTrigger>
</i:Interaction.Triggers>
<Grid Margin="30, 0, 30, 30">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.ColumnSpan="2" Content="{Binding Notification.Title}" HorizontalAlignment="Left" FontFamily="{StaticResource 'Brandon Grotesque Bold'}" FontSize="{StaticResource LargeFontSize}"/>
<Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Content="{Binding Notification.Content}" HorizontalAlignment="Center" VerticalContentAlignment="Center" FontFamily="{StaticResource 'Brandon Grotesque Bold'}" FontSize="{StaticResource LargeFontSize}"/>
<ScrollViewer x:Name="aoeu" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" CanContentScroll="True" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Notification.PossibleProfiles}" Margin="0, 0, 30, 0">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type models:ProfileAcceptPair}">
<CheckBox Style="{StaticResource RightAlignedCheckBox}" Content="{Binding Name}" IsChecked="{Binding Accepted}" HorizontalContentAlignment="Right"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Button Grid.Row="3" Grid.Column="0" HorizontalAlignment="Center" Content="{x:Static resources:DisplayStrings.CancelButton}" Style="{StaticResource ModalWindowButton}" Command="{Binding CancelCommand}" Margin="0" VerticalAlignment="Center"/>
<Button Grid.Row="3" Grid.Column="1" Content="{x:Static resources:DisplayStrings.OKButton}" Style="{StaticResource ModalWindowButton}" Command="{Binding AcceptCommand}" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
It seems the items source is updating fine and I can see the new item element hidden below the scroll viewer but I can't scroll down to it.
How can I get the scrollable height to update?
The problem wasn't with the scroll viewer. It was the items presenter from the items control inside the scroll viewer. It wasn't updating it's height on items changing.
My solution isn't ideal but it worked. I added a loaded event handler for the user control in the code behind. I then named the items control and using that found the items presenter child and called invalidate measure.
void Popup_OnLoaded(object sender, RoutedEventArgs e)
{
var itemsPresenter = (ItemsPresenter) FindChild(MyItemsControl, typeof(ItemsPresenter));
itemsPresenter.InvalidateMeasure();
}
public DependencyObject FindChild(DependencyObject o, Type childType)
{
DependencyObject foundChild = null;
if (o != null)
{
var childrenCount = VisualTreeHelper.GetChildrenCount(o);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(o, i);
if (child.GetType() != childType)
{
foundChild = FindChild(child, childType);
}
else
{
foundChild = child;
break;
}
}
}
return foundChild;
}

WPF copying controls programmatically

I created an example control that I want to copy as many times as many I will set in code. I want to duplicate entire <ToggleButton> control.
XAML:
<WrapPanel Name="varom">
<ToggleButton Margin="10">
<StackPanel Orientation="Horizontal">
<Label Content="Stop sign" />
<Image Width="16" Source="{Binding appbar_stop}" />
</StackPanel>
</ToggleButton>
<ToggleButton Margin="10">
<StackPanel Orientation="Horizontal">
<Label Content="Stop sign" />
<Image Width="16" Source="{Binding appbar_stop}" />
</StackPanel>
</ToggleButton>
</WrapPanel>
Now I copied one time <ToggleButton> manually, but if I would have just one <ToggleButton> and I want to get second without copying xaml code...
Is it possible to duplicate(copy) <ToggleButton> control using code?
C#:
namespace WpfApplication3
{
public partial class MainWindow : MetroWindow
{
public const int maxButtons = 4; // number of copies for example
public MainWindow()
{
InitializeComponent();
// code add here for example :)
}
}
}
Models:
public class ButtonViewModel
{
public string Caption { get; set; }
}
public class ViewModel
{
public ViewModel()
{
Buttons = new ObservableCollection<ButtonViewModel>
{
new ButtonViewModel { Caption = "Button 1" },
new ButtonViewModel { Caption = "Button 2" },
new ButtonViewModel { Caption = "Button 3" },
};
}
public ObservableCollection<ButtonViewModel> Buttons { get; }
}
XAML:
<ItemsControl ItemsSource="{Binding Buttons}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Margin="10">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Caption}" />
<Image Width="16"/>
</StackPanel>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

how to bind specific property in user control in itemscontrol

I have following UserControl :
<Grid x:Name="LayoutRoot">
<CheckBox x:Name="seat" Margin="2,2,2,2.901" BorderBrush="#FF003FFF" Content="{Binding Path=TypeSSeat, ElementName=UserControl}" />
</Grid>
With This CodeBehind :
[DefaultValue(Nothing)]
public enum TypeSeat
{
Nothing,FirstClass, businessclass , economyclass ,NoSeat
}
public partial class UCSeat : UserControl
{
public TypeSeat TypeSSeat
{
get
{
return (TypeSeat)GetValue(ItemTextProperty);
}
set
{
SetValue(ItemTextProperty, value);
}
}
public static readonly DependencyProperty ItemTextProperty =
DependencyProperty.Register("TypeSSeat", typeof(TypeSeat), typeof(UCSeat), new PropertyMetadata(default(TypeSeat)));
i want to fill itemscontrol with this usercontrol but after run i have just one checkBox.
this is my windows code :
<ItemsControl Name="icName" Height="366" VerticalAlignment="Top" ItemsSource="{Binding Path=UCSeat}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<local:UCSeat HorizontalAlignment="Left" Width="156.8" TypeSSeat="{Binding seat1}" ToolTip="1"/>
<local:UCSeat HorizontalAlignment="Left" Width="156.8" TypeSSeat="{Binding seat2}" ToolTip="2"/>
and with this code behind :
List<SeatList> lst = new List<SeatList>();
lst.Add(new SeatList { seat1 = TypeSeat.FirstClass, seat2 = TypeSeat.FirstClass, seat3 = TypeSeat.NoSeat, seat4 = TypeSeat.FirstClass, seat5 = TypeSeat.FirstClass, seat6 = TypeSeat.Nothing, seat7 = TypeSeat.Nothing, seat8 = TypeSeat.Nothing, seat9 = TypeSeat.Nothing, seat10 = TypeSeat.Nothing, seat11 = TypeSeat.Nothing, seat12 = TypeSeat.Nothing, seat13 = TypeSeat.Nothing, seat14 = TypeSeat.Nothing });
icName.ItemsSource = lst;
Your DataTemplate uses a grid as it's layout control. The two UCSeat user controls are placed in this grid without specifying which column they should be located in.
This means both UCSeat controls are placed on top of each other which might make it look as if only one checkbox is being displayed.
Either change the second UCSeat entry to include the Grid.Column="1" to make the second user control show in the second column
OR use a StackPanel container with Orientation="Horizontal" instead of the Grid container meaning both will layout horizontally automatically
You have all the items there, however they are all stacked on top of each other.
To properly layout items you need to set your ItemsPanelTemplate to whatever container you are placing your items in (such as a Grid), and use the ItemContainerStyle to set any specific properties of your items (such as Grid.Row and Grid.Column
Here's some sample XAML taken from my blog post about the ItemsControl
<ItemsControl ItemsSource="{Binding MyCollection}">
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ItemContainerStyle -->
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column"
Value="{Binding ColumnIndex}" />
<Setter Property="Grid.Row"
Value="{Binding RowIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
<!-- ItemTemplate -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This assumes you are binding to a collection of objects that look something like this :
public class MyObjectModel
{
public string Name { get; set; }
public int ColumnIndex{ get; set; }
public int RowIndex{ get; set; }
}
And results in something like this :
I'd highly recommend reading the actual post as well if you're new to using an ItemsControl :)

Data binding from multiple sources

I am trying to get data from two array lists into a window. The first array list contains images and the second array list contains names of movies.
The layout will show movie posters along with the names of the relevant movie underneath the poster. The code I am currently using doesn't seem to be working properly as I only get images showing in the window but no text.
This the current XAML code I have:
<Window.Resources>
<DataTemplate x:Key="ItemTemplate">
<WrapPanel Orientation="Vertical">
<Image Width="200" Height="300" Stretch="Fill" Source="{Binding}"/>
<TextBlock Text="{Binding movie_names}" HorizontalAlignment="Center"/>
</WrapPanel>
</DataTemplate>
</Window.Resources>
<Grid x:Name="movie_grid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<ListView Grid.Row="1"
Name="MovieListView"
ItemTemplate="{StaticResource ItemTemplate}"
ItemsSource="{Binding Path = movie_posters_list}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<TextBlock Name="SampleTextBlock"
Text="{Binding Path=movie_names}"
DataContext="{StaticResource ItemTemplate}" />
</Grid>
</Window>
And here is the C# code behind:
public partial class MoviePanel : Window {
public MoviePanel() {
InitializeComponent();
}
List<ImageSource> movie_posters_list = new List<ImageSource>();
List<String> movie_names = new List<String>();
String regex_pattern = #"\\([\w ]+).(?:jpg|png)$";
public void LoadImages() {
//Image current_image;
String movie_poster_path = #"C:\Users\Vax\Desktop\movie_posters";
List<String> filenames = new List<String>(System.IO.Directory.EnumerateFiles(movie_poster_path, "*.jpg"));
foreach (String filename in filenames) {
this.movie_posters_list.Add(new BitmapImage(new Uri(filename)));
Match regex_match = Regex.Match(filename.Trim(), regex_pattern);
String matched_movie_name = regex_match.Groups[1].Value;
this.movie_names.Add(matched_movie_name);
}
MovieListView.ItemsSource = movie_posters_list;
MovieListView.DataContext = movie_names;
}
}
I think the issue stems from binding the data but I'm not sure what I've done wrong.
Create a model class and wrap your Movie Name and Image into it.
public class MovieDetail
{
public ImageSource Image { get; set; }
public string Name { get; set; }
}
When calling LoadImages, add instances of this model into ListView. And modify the datatemplate to bind the Name and Image.
List<MovieDetail> movies = new List<MovieDetail>();
foreach (String filename in filenames)
{
Match regex_match = Regex.Match(filename.Trim(), regex_pattern);
String matched_movie_name = regex_match.Groups[1].Value;
movies.Add(new MovieDetail { Image = new BitmapImage(new Uri(filename)), Name = matched_movie_name });
}
MovieListView.ItemsSource = movies;
The DataTemplate,
<DataTemplate x:Key="ItemTemplate">
<WrapPanel Orientation="Vertical">
<Image Width="200"
Height="300"
Stretch="Fill"
Source="{Binding Image}" />
<TextBlock Text="{Binding Name}"
HorizontalAlignment="Center" />
</WrapPanel>
</DataTemplate>

Dynamically adding elements to a UI in C#

The Problem
I have a C# window with some text fields and buttons on it. It starts out similar to this:
When the user clicks that "+ Add Machine Function" button, I need to create a new row of controls and move the button below those:
If the user clicks "+Add Scale Unit" the program needs to add some controls to the right:
Attempts at a solution
I have tried using Windows Forms' TableLayoutPanel but it seemed to handle resizing itself to fit additional controls in odd ways, for example it would some one rows of controls much wider than the others, and would make some rows so short it cut off parts of my controls.
I have also tried simply placing the controls by themselves into the form by simply calculating their relative positions. However I feel that this is bad programming practice as it makes the layout of the form relatively hard to change later. In the case of the user deleting the row or scale unit by pressing the 'X' beside it, this method also requires the program to find each element below that one and move it up individually which is terribly inefficient.
My question is: how would I go about creating a dynamically growing/shrinking application, either through Windows Forms layouts or WPF or something else?
In WPF you can do this:
Classes
public class MachineFunction
{
public string Name { get; set; }
public int Machines { get; set; }
public ObservableCollection<ScaleUnit> ScaleUnits { get; set; }
public MachineFunction()
{
ScaleUnits = new ObservableCollection<ScaleUnit>();
}
}
public class ScaleUnit
{
public string Name { get; set; }
public int Index { get; set; }
public ScaleUnit(int index)
{
this.Index = index;
}
}
Window.xaml
<Window x:Class="WpfApplication1.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">
<StackPanel>
<ItemsControl Name="lstMachineFunctions">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Machine Function"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="Number of Machines"/>
<Button Grid.Row="1" Grid.Column="0" Click="OnDeleteMachineFunction">X</Button>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}"/>
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Machines}"/>
</Grid>
<ItemsControl ItemsSource="{Binding ScaleUnits}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="12,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Machine/Scale Unit"/>
<Button Grid.Row="1" Grid.Column="0" Click="OnDeleteScaleUnit">X</Button>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Index, StringFormat='Scale Unit {0}'}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Button VerticalAlignment="Center" Click="OnAddScaleUnit">Add Scale Unit</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button HorizontalAlignment="Left" Click="OnAddMachineFunction">Add Machine Function</Button>
</StackPanel>
</Window>
Window.cs
public partial class MainWindow : Window
{
public ObservableCollection<MachineFunction> MachineFunctions { get; set; }
public MainWindow()
{
InitializeComponent();
lstMachineFunctions.ItemsSource = MachineFunctions = new ObservableCollection<MachineFunction>();
}
private void OnDeleteMachineFunction(object sender, RoutedEventArgs e)
{
MachineFunctions.Remove((sender as FrameworkElement).DataContext as MachineFunction);
}
private void OnAddMachineFunction(object sender, RoutedEventArgs e)
{
MachineFunctions.Add(new MachineFunction());
}
private void OnAddScaleUnit(object sender, RoutedEventArgs e)
{
var mf = (sender as FrameworkElement).DataContext as MachineFunction;
mf.ScaleUnits.Add(new ScaleUnit(mf.ScaleUnits.Count));
}
private void OnDeleteScaleUnit(object sender, RoutedEventArgs e)
{
var delScaleUnit = (sender as FrameworkElement).DataContext as ScaleUnit;
var mf = MachineFunctions.FirstOrDefault(_ => _.ScaleUnits.Contains(delScaleUnit));
if( mf != null )
{
mf.ScaleUnits.Remove(delScaleUnit);
foreach (var scaleUnit in mf.ScaleUnits)
{
scaleUnit.Index = mf.ScaleUnits.IndexOf(scaleUnit);
}
}
}
}
I did the same thing recently in WinForms and the way I did it was as follows:
Create a UserControl that contains the controls I wanted to repeat
Add a FlowLayoutPanel to the main form to contain all the user controls (and to simplify their positioning)
Add a new instance of your custom UserControl to the FlowLayoutPanel every time you want a new "row" of controls
flowLayoutPanel1.Controls.Add(
new MachineFunctionUC {
Parent = flowLayoutPanel1
});
To remove a row of control call this.Dispose(); from within the user control (that's the instruction executed by the "X" button).
If you want the UserControls to be arranged vertically set the following properties:
flowLayoutPanel1.AutoScroll = true;
flowLayoutPanel1.WrapContents = false;
flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
And to access them use flowLayoutPanel1.Controls[..]
The correct way to achieve your requirements in WPF is for you to define a custom data type class to represent your machine function. Provide it with how ever many properties that you need to represent your machine fields. When you have done this, you then need to move the code that generated your machine function UI into a DataTemplate for the type of your class and data bind all of the relevant properties:
<DataTemplate DataType="{Binding YourPrefix:MachineFunction}">
...
</DataTemplate>
Then, you need to create a collection property to hold your machine function items and data bind that to some kind of collection control. Once you have done this, then to add another row, you just need to add another item to the collection:
<ItemsControl ItemsSource="{Binding MachineFunctions}">
<ItemsControl.Resources>
<DataTemplate DataType="{Binding YourPrefix:MachineFunction}">
...
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
<Button Content="+ Add Machine Function" ... />
...
MachineFunctions.Add(new MachineFunction());
Please see the Data Binding Overview page on MSDN for further help with data binding.
Create a function which will define a row for you. Consider the code and use its where to place another control and do as for buttons also and count it position.
Button button1=new Button();
button1.Text="dynamic button";
button1.Left=10; button1.Top=10; //the button's location
this.Controls.Add(button1); //this is how you can add control

Categories

Resources