Create StackPanels dynamically and refer to any of them in code behind - c#

In its simplest form...
I would like to create as many StackPanels as I want and then add Rectangles in them. Then to be able to change the Fill color of any one of the Rectangles when I click the Start Button for instance. All in Code Behind.
Any help would be appreciated.
For example, if our favorite beer wrote the framework I could do it like this:
XAML:
<Page
x:Class="Test2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Test2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Name="StartButton" Content="Start" Click="StartButton_Click" Height="30" Width="200" Margin="5"/>
</StackPanel>
<StackPanel Grid.Row="1" Name="myStackPanel" VerticalAlignment="Top"/>
</Grid>
</Page>
Code Behind:
namespace Test2
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
for (var i = 0; i < 5; i++) // The 5 here could be any number
{
myStackPanel.Children.Add(new StackPanel
{
Name = "myPanel" + i,
Orientation = Orientation.Horizontal
});
for (var j = 0; j < 10; j++) // The 10 here could be any number
{
("myPanel" + i).Children.Add(new Rectangle
{
Name = "myRectangle" + i + "-" + j,
Fill = new SolidColorBrush(Colors.Black),
Width = 20,
Height = 20,
Margin = new Thickness(1)
});
}
}
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
// E.G. To change the Fill color of Rectangle4 in StackPanel2
("myRectangle" + 2 + "-" + 4).Fill = new SolidColorBrush(Colors.Red);
}
}
}

Firstly, to add Rectangle shapes, we can create an instance of StackPanel and manipulate its Children elements:
for (var i = 0; i < 5; i++) // The 5 here could be any number
{
StackPanel sp = new StackPanel
{
Name = "myPanel" + i,
Orientation = Orientation.Horizontal
};
myStackPanel.Children.Add(sp);
for (var j = 0; j < 10; j++) // The 10 here could be any number
{
sp.Children.Add(new Rectangle
{
Name = "myRectangle" + i + "-" + j,
Fill = new SolidColorBrush(Colors.Black),
Width = 20,
Height = 20,
Margin = new Thickness(1)
});
}
}
Then to be able to change the Fill color of any one of the Rectangles when I click the Start Button for instance. All in Code Behind.
As tgpdyk mentioned, we need to use VisualTreeHelper to find the specified rectangle shape.
Helper class:
public static class FrameworkElementExtensions
{
public static T TraverseCTFindShape<T>(DependencyObject root, String name) where T : Windows.UI.Xaml.Shapes.Shape
{
T control = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
{
var child = VisualTreeHelper.GetChild(root, i);
string childName = child.GetValue(FrameworkElement.NameProperty) as string;
control = child as T;
if (childName == name)
{
return control;
}
else
{
control = TraverseCTFindShape<T>(child, name);
if (control != null)
{
return control;
}
}
}
return control;
}
}
How to use it:
private void StartButton_Click(object sender, RoutedEventArgs e)
{
// E.G. To change the Fill color of Rectangle4 in StackPanel2
var rec = FrameworkElementExtensions.TraverseCTFindShape<Shape>(myStackPanel, "myRectangle" + 2 + "-" + 4);
rec.Fill = new SolidColorBrush(Colors.Red);
}
I've uploaded my sample to Github repository

That is not how you approach this in WPF, at all.
You usually do not concern yourself with any UI components but only the data. In this case you data bind an ItemsControl to a list of rows, each row containing a list of cells. In the ItemsControl definition you then set an ItemTemplate that contains another ItemsControl binding to the cells. In the nested ItemsControl you then can set an ItemTemplate where you bind the Background to a (notifying) property of your cells which you then just need to change in code.
Check out these overviews:
Data Binding Overview
Data Templating Overview
You may also want to look into the Model-View-ViewModel pattern to ensure a suitable application architecture.

Related

How to scroll DataGrid inside ScrollView in right way?

I think it is a pretty common situation, but I can't find a solution that I need.
My case is, I have a DataGrid inside ScrollViewer. DataGrid has such params
MinHeight="350"
MaxHeight="350"
So, it is means that I have a dataGrid with constant height inside ScrollViewer. And DataGrid can contain (example) 300 items, so it has a scroll and ScrollViewer also has a scroll.
What I need is when user put a mouse on DataGrid and scroll down, so content inside DataGrid scrolling up to the last item and if came to last item it means that now we should get scroll event to ScrollViewer and continuous scroll whole page...
I found a few solutions on SO like this two
Mouse scroll not working in a scroll viewer with a wpf datagrid and additional UI elements
ScrollViewer mouse wheel not working
I checked an answers, but them doesn't fit to my problem. Because what I get is - when user put mouse on DataGrid and try scroll, so DataGrid did not get scroll event ever, just ScrollViewer get scroll event...
How to fix it?
XAML
<Window x:Class="so_wpf_test_1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:so_wpf_test_1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Border Padding="10" Background="Yellow">
<ScrollViewer x:Name="sv">
<StackPanel Orientation="Vertical">
<DataGrid x:Name="dg" MinHeight="350" MaxHeight="350" ScrollViewer.ScrollChanged="dg_ScrollChanged">
</DataGrid>
<Button>A button that doesn't do anything</Button>
<DataGrid x:Name="dg2" MinHeight="350" MaxHeight="350" ScrollViewer.ScrollChanged="dg_ScrollChanged">
</DataGrid>
</StackPanel>
</ScrollViewer>
</Border>
</Window>
Code-behind
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace so_wpf_test_1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var items = new ObservableCollection<Item>();
for (int i = 1; i <= 50; ++i)
{
items.Add(new Item($"test {i}", $"abcd {i}", $"dcba {i}"));
}
dg.ItemsSource = items;
dg2.ItemsSource = items;
dg.PreviewMouseWheel += Dg_PreviewMouseWheel;
dg2.PreviewMouseWheel += Dg_PreviewMouseWheel;
}
private void Dg_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var m_dg = sender as DataGrid;
var scroll = GetScrollViewer(m_dg);
// if scrolling to bottom and beyond...
if (e.Delta < 0 && scroll.VerticalOffset == scroll.ScrollableHeight)
{
sv.ScrollToVerticalOffset(sv.VerticalOffset - e.Delta);
}
// if scrolling to top and beyond...
else if (e.Delta > 0 && scroll.VerticalOffset == 0)
{
sv.ScrollToVerticalOffset(sv.VerticalOffset - e.Delta);
}
else
{
// nothing special: scroll the dg if it is the case (WPF does this automatically)
}
int idx = 0;
// if scrolling down
if (e.Delta < 0)
{
// see the sketch
idx = dictLastVisible[m_dg] + 1;
Debug.WriteLine($"FROM {(m_dg == dg ? 1 : 2)} DOWN {idx}");
}
// if scrolling up
else if (e.Delta > 0)
{
// see the sketch
idx = dictFirstVisible[m_dg] - 1;
Debug.WriteLine($"FROM {(m_dg == dg ? 1 : 2)} UP {idx}");
}
// if the index does not represent nothing
if (idx != 0)
{
// transform index to be 0-based
--idx;
// scroll that row into view
m_dg.ScrollIntoView(m_dg.Items[idx]);
}
}
/// <summary>
/// Source: https://stackoverflow.com/a/41136328/258462
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
public static ScrollViewer GetScrollViewer(UIElement element)
{
if (element == null) return null;
ScrollViewer retour = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element) && retour == null; i++)
{
if (VisualTreeHelper.GetChild(element, i) is ScrollViewer)
{
retour = (ScrollViewer)(VisualTreeHelper.GetChild(element, i));
}
else
{
retour = GetScrollViewer(VisualTreeHelper.GetChild(element, i) as UIElement);
}
}
return retour;
}
Dictionary<DataGrid, int> dictLastVisible = new Dictionary<DataGrid, int>();
Dictionary<DataGrid, int> dictFirstVisible = new Dictionary<DataGrid, int>();
private void dg_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
var dg = (DataGrid)sender;
int idxb = -1, idxe = -1; // b = beginning, e = end; both invalid initially
// from the first row towards the last row
for (int i = 0; i < dg.Items.Count; i++)
{
var v = (DataGridRow)dg.ItemContainerGenerator.ContainerFromItem(dg.Items[i]);
if (v != null)
{
idxb = i + 1; // compute the beginning row in the viewport
break;
}
}
// from the beginning row towards the last row
for (int i = idxb + 1; i < dg.Items.Count; i++)
{
var v = (DataGridRow)dg.ItemContainerGenerator.ContainerFromItem(dg.Items[i]);
if (v == null)
{
idxe = i - 1 + 1; // compute the end row in the viewport
break;
}
}
// store the two indices in two dictionaries
dictFirstVisible[dg] = idxb;
dictLastVisible[dg] = idxe;
}
}
public class Item
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public Item(string a, string b, string c)
{
A = a;
B = b;
C = c;
}
}
}
Possibly helping sketch
If the code does not run or has bugs, or the comments are not clear enough, please post a comment. I hope you will be able to extend the code for a dynamic number of DataGrids if you have this requirement.

Add items to a Thumb dynamically

I created a two thumbs dynamically that look like rectangles and handled the drag and drop events so they can move inside a Canvas. Later when I press some button on the UI, I want to add some strings dynamically to each Thumb inside the Canvas. Is there a way to do it. Please help.
Xaml:
<uwpControls:LayoutTransformControl x:Name="MainLayoutControl" Grid.Row="4" Height="400" Width="600" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid Grid.Row="4" x:Name="gridBarImagePanel" BorderBrush="Black"
BorderThickness="2">
<Image x:Name="BarCodeImage"
RenderTransformOrigin="0.5,0.5"></Image>
<Canvas x:Name="cnvBarCodeImage">
</Canvas>
</Grid>
</uwpControls:LayoutTransformControl>
Code Behind:
private void CreateUIShapes(int numberOfWindows, List<Dimensions> dimensions)
{
Thumb th = null;
for (int i = 0; i < numberOfWindows; i++)
{
th = new Thumb();
th.Name = i.ToString();
var item = dimensions[i];
th.Width = item.Width;
th.Height = item.Height;
th.Foreground = new SolidColorBrush(Windows.UI.Colors.Transparent);
th.BorderBrush = item.BorderColor;
th.BorderThickness = new Thickness(3);
th.DragDelta += (sender, e) => Th_DragDelta(sender, e, dimensions);
th.DragCompleted += (sender, e) => Th_DragCompleted(sender, e, item.IsImageRotated);
//RotateWindowsByAngle(90, th, dimensions, i);
Canvas.SetLeft(th, item.left);
Canvas.SetTop(th, item.Top);
cnvBarCodeImage.Children.Add(th);
}
}
private void BtnScan_Click(object sender, RoutedEventArgs e)
{
//How can I add some text to the Thumb controls at this point. There is no Children Property.
}
Since the Thumb isn't a ContentControl, you will have to supply it with a custom ControlTemplate to add text to it.
Here is a simple example showing how to do this in code:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Markup;
using System.Windows.Media;
namespace WpfApp4
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var thumb = new Thumb
{
Width = 100,
Height = 50,
Background = new SolidColorBrush(Colors.Red),
Foreground = new SolidColorBrush(Colors.White),
Template = GetThumbTemplate("")
};
Canvas.SetLeft(thumb, 100);
Canvas.SetTop(thumb, 100);
RootCanvas.Children.Add(thumb);
thumb.Template = GetThumbTemplate("Hello world!");
}
private ControlTemplate GetThumbTemplate(string text)
{
var template = "<ControlTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" TargetType=\"Thumb\">" +
"<Border Background=\"{TemplateBinding Background}\">" +
"<TextBlock VerticalAlignment=\"Center\" HorizontalAlignment=\"Center\" Text=\"" + text + "\" />" +
"</Border>" +
"</ControlTemplate>";
return XamlReader.Parse(template) as ControlTemplate;
}
}
}
When I create the Thumb I set the Template with GetThumbTemplate and pass in an empty string. GetThumbTemplate creates a simple ControlTemplate with a Border and a TextBlock. I then parse the XAML and return it.
After I add it to the Canvas, I update the Template of the Thumb using the GetThumbTemplate method, passing in the string I want to display.
I hope this helps!

Programmatically generated expanders with scrollable content resizing to window

I'm looking for a better way to make a programmatically generated window with the following behavior.
That is: List of expanders that can be initialized programmatically, each of which contains scrollable content larger than can be displayed in the window (in this case a datagrid). When an expander is expanded it's contents are limited to the available size of the window, while allowing all the rest of the expanders to be seen and manipulated. Additionally only one expander can be open at any given time.
This functionality seems that it could be useful in a lot of application menus, so I was surprised how difficult it was to implement. Is there a better way than what I did?
XAML (surprisingly simple):
<Window x:Class="ExpanderScrollExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="200">
<Grid>
<ItemsControl ItemsSource="{Binding Dict}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Loaded="GridLoaded" ScrollViewer.CanContentScroll="False"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Header ="{Binding Key, Mode=OneWay}" Expanded="Expander_Expanded" Collapsed="Expander_Collapsed">
<DataGrid ItemsSource="{Binding Path=Value}"/>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Code Behind (with most of the magic):
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ExpanderScrollExample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
private void GridLoaded(object sender, RoutedEventArgs e)
{
Grid grid = sender as Grid;
grid.LayoutUpdated += (s, e2) =>
{
var childCount = grid.Children.Count;
int rowsToAdd = (childCount - grid.RowDefinitions.Count);
for (int row = 0; row < rowsToAdd; row++)
{
RowDefinition rowDefinition = new RowDefinition();
rowDefinition.Height = new GridLength(0, GridUnitType.Auto);
grid.RowDefinitions.Add(rowDefinition);
}
for (int i = 0; i < childCount; i++)
{
var child = grid.Children[i] as FrameworkElement;
Grid.SetRow(child, i);
}
};
}
private void Expander_Expanded(object sender, RoutedEventArgs e)
{
ContentPresenter parentDataContext = VisualTreeHelper.GetParent(sender as DependencyObject) as ContentPresenter;
Grid grid = VisualTreeHelper.GetParent(parentDataContext as DependencyObject) as Grid;
grid.RowDefinitions[Grid.GetRow(parentDataContext)].Height = new GridLength(1, GridUnitType.Star);
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(grid); i++)
{
DependencyObject neighborDataContext = VisualTreeHelper.GetChild(grid, i);
for (int j = 0; j < VisualTreeHelper.GetChildrenCount(neighborDataContext); j++)
{
DependencyObject neighborExpander = VisualTreeHelper.GetChild(neighborDataContext, j);
if (neighborExpander is Expander && neighborExpander != sender)
{
((Expander)neighborExpander).IsExpanded = false;
this.Collapse(neighborExpander as Expander);
}
}
}
}
private void Expander_Collapsed(object sender, RoutedEventArgs e)
{
this.Collapse(sender as Expander);
}
private void Collapse(Expander expander)
{
ContentPresenter parent = VisualTreeHelper.GetParent(expander as DependencyObject) as ContentPresenter;
Grid grandparent = VisualTreeHelper.GetParent(parent as DependencyObject) as Grid;
grandparent.RowDefinitions[Grid.GetRow(parent)].Height = new GridLength(0, GridUnitType.Auto);
}
}
}
ViewModel (only for data generation)
using System.Collections.Generic;
namespace ExpanderScrollExample
{
class MainWindowViewModel
{
public Dictionary<string, List<MyClass>> Dict { get; }
public MainWindowViewModel()
{
Dict = new Dictionary<string, List<MyClass>>();
for ( int i = 0; i < 5; i++ )
{
string key = "Header " + i.ToString();
Dict[key] = new List<MyClass>();
for ( int j = 0; j < 100; j++)
{
Dict[key].Add(new MyClass(j, i*100 + j));
}
}
}
public class MyClass
{
public int Column1 {get; set;}
public int Column2 { get; set; }
public MyClass( int column1, int column2)
{
Column1 = column1;
Column2 = column2;
}
}
}
}
I also typically try to confirm with MVVM pattern, but was unable to do so in this case.
Generating items controls in grid is taken from here.
I also considered using style triggers to expand/collapse and set size as described in this answer but I couldn't think of a good way how to bind the dynamically generated rows with expanders.
Is there a better way to do this?
1. Only one Expander expanded at a given time
To make sure that only one Expander is expanded at a given time, you can create an Attached Behavior. I implemented one for reference.
ExpanderGroupBehavior (inspired by RadioButton)
<Expander wpf:ExpanderGroupBehavior.GroupName="ExpanderGroup01" />
This makes sure that only one Expander within the same group is expanded.
2. Expanded Expander fill available space
To achieve that, you may create your own Panel which handles that for you.
See How to get controls in WPF to fill available space? and https://learn.microsoft.com/en-us/dotnet/framework/wpf/controls/how-to-create-a-custom-panel-element

c# wpf - ListView.ScrollIntoView(LastItem) does not work properly

like some other people here i have a ListView (updated via binding in a GridView).
I want to keep the last inserted Item in the View. So i tried
LView.ScrollIntoView(LView.Items[LView.Items.Count - 1]);
This is working almost fine. Altough the first item which would have to be scrolled into view is only shown like 80% of its whole row (depending on how high i define the whole ListView, i almost got 100%).
The real problem is that the following items which should get scrolled into view are not shown. It is also noticable at the Scrollbar itself which is not at the bottom.
Last Item is not shown
Here is the code of my MainWindow.
public partial class MainWindow : Window
{
private InterfaceCtrl ICtrl;
private ListView LView;
public MainWindow()
{
InitializeComponent();
this.ICtrl = new InterfaceCtrl();
this.ICtrl.ProgressCollection.CollectionChanged += this.CollectionChanged;
Grid MainGrid = new Grid();
this.Content = MainGrid;
GridView gv = new GridView();
Binding StartTimeStampBinding = new Binding() { Path = new PropertyPath("StartTS"), Mode = BindingMode.OneWay, StringFormat = "dd.MM.yyyy - HH:mm:ss.fff" };
GridViewColumn gvTCStartTS = new GridViewColumn() { Header = "Time", Width = 150.00, DisplayMemberBinding = StartTimeStampBinding };
gv.Columns.Add(gvTCStartTS);
LView = new ListView() { Height = 192, Width = 250, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, View = gv, ItemsSource = this.ICtrl.ProgressCollection };
MainGrid.Children.Add(LView);
ICtrl.StartMyThread();
}
private void CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Action(delegate ()
{
if (LView != null && LView.Items.Count > 0)
{
LView.UpdateLayout();
//LView.ScrollIntoView(LView.Items[LView.Items.Count - 1]);
LView.SelectedIndex = LView.Items.Count;
LView.ScrollIntoView(LView.SelectedItem);
}
}));
}
}
Thank you.
EDIT:
It seemed to be a timing problem, although all the wanted data was in the LView at the right time i tried a workaround with a Textbox bound to the Timestamp.
TextBox tb = new TextBox(); // { Width = 250, Height = 28, Margin= new Thickness(10,100,1,0)};
tb.SetBinding( TextBox.TextProperty , new Binding("LastMsgTimestamp") { Source = this.ICtrl, Mode = BindingMode.OneWay, StringFormat = "dd.MM.yyyy - HH:mm:ss.fff" });
tb.TextChanged += this.UpdateScrollbar;
tb.Visibility = Visibility.Hidden;
It seems to me like there is a timing issue within the binding to the LView and the fired Event of the ObservableCollection. This also includes the PropertyChanged of the ObservableCollection.
I tried the events TargetUpdated and SoruceUpdated directly within LView but those didn't came up at all.
You could try to call any of the ScrollToBottom() or ScrollToVerticalOffset() methods of the ListView's internal ScrollViewer element:
private void CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Action(delegate ()
{
if (LView != null && LView.Items.Count > 0)
{
LView.UpdateLayout();
ScrollViewer sv = GetChildOfType<ScrollViewer>(LView);
if (sv != null)
sv.ScrollToBottom();
LView.SelectedIndex = LView.Items.Count;
LView.ScrollIntoView(LView.SelectedItem);
}
}));
}
private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null)
return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null)
return result;
}
return null;
}
I have made the following sample. You could try to call ScrollToBottom in inner ScrollViewer as #mm8 points out. Nevertheless when saw the answer I was already making my sample, so here it is:
Codebehind
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ListViewScroll
{
public partial class MainWindow : Window
{
public ObservableCollection<string> Names { get; set; }
public MainWindow()
{
InitializeComponent();
Names = new ObservableCollection<string>();
ListView.ItemsSource = Names;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Names.Add("Some Name" + ++someInt);
// Get the border of the listview (first child of a listview)
var border = VisualTreeHelper.GetChild(ListView, 0) as Decorator;
// Get scrollviewer
var scrollViewer = border.Child as ScrollViewer;
scrollViewer.ScrollToBottom();
}
private static int someInt;
}
}
XAML
<Window x:Class="ListViewScroll.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>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListView Grid.Row="0" Name="ListView"/>
<Button Content="Add" FontSize="20" Grid.Row="1"
Click="ButtonBase_OnClick"/>
</Grid>
</Window>
In this case I am handling the scrolling in the button click event but you may change this to fit your requirements
It works, I have tested.
Hope this helps

WPF: Dynamical Label addition in Grid

I have to create a table to display the KEY VALUE kind of thing.
I tried the below code but messed up with overlapping output. I believe, I need to create the Grid RowDefinitions and ColumnDefinitions but not able to achieve it. Please help me.
XAML:
<Window x:Class="GrideLabel.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 Name="LabelGrid"></Grid>
</Window>
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
AddLabelDynamically();
}
private void AddLabelDynamically()
{
for (int i = 0; i < 3; i++)
{
Label nameLabel = new Label(); nameLabel.Content = "KEY :"+i.ToString();
Label dataLabel = new Label(); dataLabel.Content = "VALUE :"+i.ToString();
//I want to creatre the Seperate coloum and row to display KEY
// VALUE Pair distinctly
this.LabelGrid.Children.Add(nameLabel);
this.LabelGrid.Children.Add(dataLabel);
}
}
}
You have to define Row and Column definitions and assign Rows and Columns to child Controls. Following code does that:
private void AddLabelDynamically()
{
this.LabelGrid.ColumnDefinitions.Clear();
this.LabelGrid.RowDefinitions.Clear();
this.LabelGrid.ColumnDefinitions.Add(new ColumnDefinition());
this.LabelGrid.ColumnDefinitions.Add(new ColumnDefinition());
for (int i = 0; i < 3; i++)
{
this.LabelGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
Label nameLabel = new Label(); nameLabel.Content = "KEY :" + i.ToString();
Label dataLabel = new Label(); dataLabel.Content = "VALUE :" + i.ToString();
Grid.SetRow(nameLabel, i);
Grid.SetRow(dataLabel, i);
Grid.SetColumn(nameLabel, 0);
Grid.SetColumn(dataLabel, 1);
//I want to creatre the Seperate coloum and row to display KEY
// VALUE Pair distinctly
this.LabelGrid.Children.Add(nameLabel);
this.LabelGrid.Children.Add(dataLabel);
}
}

Categories