This was to stretch my beginner abilities. What started as a single ListBox
became a grid with 3 columns. Each column is to display the contents of a property that was populated. The first two columns are using the same List<FooData>
. The third column to display List<BarData>
came out of pushing myself to try a completely unrelated data type and create a template for it. Any suggestions on better organization are welcome.
The helper functions were created to populate information that would allow me to see distinct information.
MyViewModel.cs
namespace WpfApp1 { public class MyViewModel { public List<FooData> FooData { get { return GenerateFooList('A', 'D'); } } public List<FooData> DifferentFooData { get { return GenerateFooList(91, 102); } } #region FooHelpers private List<FooData> GenerateFooList(char start, char end) { return GenerateFooList((int)start, (int)end); } private List<FooData> GenerateFooList(int start, int end) { List<FooData> list = new List<FooData>(); for (int i = start; i <= end; i++) { list.Add(new FooData((char)i)); } return list; } #endregion public List<BarData> BarData { get { return GenerateBarList(5); } } #region BarHelpers private List<BarData> GenerateBarList(int numberOfEntries) { List<BarData> barList = new List<BarData>(); for (int i = 0; i <= numberOfEntries; i++) { string barName = GenerateBarName(); string barAddress = GenerateBarAddress(); barList.Add(new BarData(barName, barAddress)); } return barList; } private string GenerateBarName() { return GetRandom(GroupingOf.GroupOf.characters, 3); } private string GenerateBarAddress() { string streetNumber = GetRandom(GroupingOf.GroupOf.digits, 4); string streetName = GetRandom(GroupingOf.GroupOf.characters, new Random().Next(4, 12)); return $ "{streetNumber} {streetName}"; } private string GetRandom(GroupingOf.GroupOf randomThing, int ofLength) { Random r = new Random(DateTime.Now.Millisecond); StringBuilder sb = new StringBuilder(); for (int i = 0; i < ofLength; i++) { switch (randomThing) { case GroupingOf.GroupOf.characters: sb.Append((char)r.Next('A', 'Z' + 1)); break; case GroupingOf.GroupOf.digits: sb.Append(r.Next(0, 9)); break; default: throw new NotImplementedException("Need to add something Enum 'GroupOf'"); } System.Threading.Thread.Sleep(50); } return sb.ToString(); } #endregion } public class FooData { public char GetChar { get; } public int GetCharNumber { get; } public DateTime NestedTime { get; } public FooData(char character) { GetChar = character; GetCharNumber = character; NestedTime = DateTime.Now; } } public class BarData { public string Name { get; } public string Address { get; } public BarData(string name, string address) { Name = name; Address = address; } } }
XAML file where I’ve attempted to generalize what I could into a template. Is there anything I can do further to make more generic and/or reusable?
<Window x:Class="WpfApp1.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:WpfApp1" xmlns:po="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" mc:Ignorable="d" Title="MainWindow" Width="650" Height="Auto" d:DesignHeight="161.5"> <Window.Resources> <DataTemplate x:Key="FooTemplate"> <Border BorderBrush="Black" BorderThickness="1"> <Grid> <Grid.Resources> <Style x:Key="label" TargetType="TextBlock"> <Setter Property="HorizontalAlignment" Value="Right"/> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="Character: " Style="{StaticResource label}"/> <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding GetChar}"/> <TextBlock Grid.Row="1" Grid.Column="0" Text="Number: " Style="{StaticResource label}"/> <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding GetCharNumber}"/> <TextBlock Grid.Row="2" Grid.Column="0" Text="Time (ms): " Style="{StaticResource label}"/> <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding NestedTime.Millisecond}"/> </Grid> </Border> </DataTemplate> <DataTemplate x:Key="BarTemplate"> <Border BorderBrush="Black" BorderThickness="1"> <StackPanel Orientation="Horizontal" Background="BlanchedAlmond" HorizontalAlignment="Center"> <StackPanel.Resources> <Style TargetType="TextBlock"> <Setter Property="Margin" Value="10,0"/> </Style> </StackPanel.Resources> <TextBlock Text="{Binding Name}"/> <TextBlock Text="{Binding Address}"/> </StackPanel> </Border> </DataTemplate> </Window.Resources> <Grid> <Grid.Resources> <Style TargetType="Label"> <Setter Property="FontSize" Value="20"/> </Style> <Style TargetType="ListBox"> <Setter Property="Margin" Value="5"/> <Setter Property="BorderBrush" Value="CadetBlue"/> <Setter Property="BorderThickness" Value="2"/> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="MinHeight" Value="50"/> </Style> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0"> <Label Content="Original Foo list:"/> <ListBox ItemsSource="{Binding FooData}" ItemTemplate="{StaticResource FooTemplate}"/> </StackPanel> <StackPanel Grid.Column="1"> <Label Content="Second Foo list:"/> <ListBox ItemsSource="{Binding DifferentFooData}" ItemTemplate="{StaticResource FooTemplate}"/> </StackPanel> <StackPanel Grid.Column="2"> <Label Content="Bar list:"/> <ListBox ItemsSource="{Binding BarData}" ItemTemplate="{StaticResource BarTemplate}"/> </StackPanel> </Grid> </Window>
I’m beginning to grok DataContext
. It says in the section ‘Specifying the Binding Source’ that:
…without the binding source object being specified, the binding would do nothing.
Is it best to set the DataContext
for the host element that way it supplies it to all child elements?
namespace WpfApp1 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new MyViewModel(); } } }
Helper class that allowed population of dummy data:
namespace WpfApp1 { public class GroupingOf { public enum GroupOf { characters, digits }; } }