Add items to ItemsControl - wpf

I have an application for telephone call. Each call(line) has its own unique information. Say a colorful icon plus and line number. The numbers are in a queue, I used parallel programming skills to deal these items. When processing the item, the information is shown on the screen. Here I prefer ItemsControl.
The expected result likes the image. I want to
I borrowed the code for phone icon.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<SolidColorBrush x:Key="RedBrush" Color="Red" />
<SolidColorBrush x:Key="AmberBrush" Color="#FFFFC500" />
<SolidColorBrush x:Key="GreenBrush" Color="Green" />
<Geometry x:Key="PhoneIcon">F1M52.5221,11.1016C52.0637,10.6796 44.4973,4.55737 29.4347,12.7369 26.3098,14.4296 23,17.224 20.095,20.1692 17.1497,23.073 14.3555,26.3842 12.6626,29.509 4.48303,44.5703 10.6093,52.1393 11.0298,52.5962 11.0298,52.5962 12.9778,55.5885 14.7057,53.8579L23.3555,45.2134C24.897,43.6692 22.7721,39.2134 18.2563,39.3541 17.1301,39.3906 15.5481,38.9531 17.0571,35.5156 18.3945,32.4623 22.3436,27.4766 24.8879,24.9648 27.4048,22.418 32.3904,18.4713 35.4426,17.1301 38.8787,15.6223 39.3175,17.2031 39.2811,18.332 39.1393,22.8462 43.5962,24.9686 45.1366,23.4283L53.7864,14.7787C55.5142,13.052,52.5221,11.1016,52.5221,11.1016z</Geometry>
My question: If I know the color of the phone icon and the phone number, how to add it to the itemscontrol? The phone number needs to be bind, I assume I have a class:
public class Lines
{
public string color { get; set; }
public string linenumber { get; set; }
}
And I defined the ItemsControls as:
<DockPanel>
<ItemsControl Height="300">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
Not sure the next step?

Assuming you are not using MVVM here, just XAML forms with code behind classes - you need to alter your code behind first a little. You need an object to represent a "line" - and make the colour a brush, not a string:
public class Line
{
public string LineNumber { get; set; }
public System.Windows.Media.Brush LineColour { get; set; }
}
Then you need code to build a collection of these which your ItemsControl can display. It might look something like this:
public partial class MainWindow : Window
{
private List<Line> _lines;
public MainWindow()
{
InitializeComponent();
_lines = new List<Line>();
// you can swap this for iterating around a database query or whatever you use to store the lines / calls
_lines.Add(new Line() { LineNumber = "line1", LineColour = new SolidColorBrush(Colors.Red) });
_lines.Add(new Line() { LineNumber = "line2", LineColour = new SolidColorBrush(Colors.Green) });
_lines.Add(new Line() { LineNumber = "line3", LineColour = new SolidColorBrush(Color.FromRgb(255, 188, 59)) });
// this part binds this list to your itemsControl
items.ItemsSource = _lines;
}
Then your XAML is fairly easy, you just define an ItemsControl called "items" and define a style which will be applied to each item. This will contain the line number apply the brush to the image, which you will make a "Path":
<!-- this bit defines how each item looks-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0" Fill="{Binding LineColour}" Data="F1M52.5221,11.1016C52.0637,10.6796 44.4973,4.55737 29.4347,12.7369 26.3098,14.4296 23,17.224 20.095,20.1692 17.1497,23.073 14.3555,26.3842 12.6626,29.509 4.48303,44.5703 10.6093,52.1393 11.0298,52.5962 11.0298,52.5962 12.9778,55.5885 14.7057,53.8579L23.3555,45.2134C24.897,43.6692 22.7721,39.2134 18.2563,39.3541 17.1301,39.3906 15.5481,38.9531 17.0571,35.5156 18.3945,32.4623 22.3436,27.4766 24.8879,24.9648 27.4048,22.418 32.3904,18.4713 35.4426,17.1301 38.8787,15.6223 39.3175,17.2031 39.2811,18.332 39.1393,22.8462 43.5962,24.9686 45.1366,23.4283L53.7864,14.7787C55.5142,13.052,52.5221,11.1016,52.5221,11.1016z"/>
<TextBlock Grid.Column="1" Text="{Binding LineNumber}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!-- this bit defines the list appearance, we'll go vertical in a stack panel! -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
If you are using MVVM, everything still applies, but instead of assigning the ItemsSource in code behind, you would bind to the _lines collection of your view model - and you would make that an ObservableCollection rather than List if you wanted to add/remove dynamically.
But I have given you the simplest case as that's what your original question suggests!

Related

WPF - How to implement DataTemplate with complex logic?

I am currently transferring my app from WinForms to WPF.
Since I'm new in WPF, I stucked at creating DataTemplates for my treeView items. The screenshot shows how my treeview looked in WinForms version, and I need to get close result in WPF.
(My WinForms treeview)
As you can see, my DataTemplate's logic should take into account these factors:
Node type / defines which icon and fields combination will be displayed for particular item (node). App has about 7-8 node types. Type stored in separate node's field.
Variable values / I need to replace with text if null, etc
Numeric variable values / e.g.: set gray color if zero, etc.
Other properties / e.g.: adding textblocks depending on boolean fields.
And so on...
All these factors result into huge amount of possible item params combinations.
Also I'm using DevComponents WPF DotNetBar AdvTree to divide item properties into columns. I presume I should create 'sub templates' for different field sets and compose from them the entire DataTemplate for each column.
I've learned about triggers, and have to say that implementing my logic with triggers will make my subtemplates huge anyway.
(Current state of my WPF treeview)
So here are my questions:
Are there any ways to dynamically compose complex templates with C# code (without creating raw XAML and loading it at runtime)?
Maybe I should use completely different way (instead of using DataTemplate)? In Winforms I just used OwnerDraw mode, so the task was MUCH easier than in WPF :(
And how to display nested properties inside template? e.g.: Item.Prop.Subprop1.Subprop2.Targetprop.
PS: English is not my first language, sorry for your eyes.
1) The answer is yes.
For exemple if you want to define a template in your window for a simple string
public MainWindow()
{
InitializeComponent();
DataTemplate template = new DataTemplate(typeof(string));
FrameworkElementFactory borderFactory = new FrameworkElementFactory(typeof(Border));
borderFactory.SetValue(Border.PaddingProperty, new Thickness(1));
borderFactory.SetValue(Border.BorderThicknessProperty, new Thickness(1));
borderFactory.SetValue(Border.BorderBrushProperty, Brushes.Red);
FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBlock));
textFactory.SetBinding(TextBlock.TextProperty, new Binding
{
Mode = BindingMode.OneWay
});
borderFactory.AppendChild(textFactory);
template.VisualTree = borderFactory;
myControl.ContentTemplate = template;
}
And in the Window you just put something like
<ContentControl x:Name="myControl" Content="Test text" Margin="10"/>
Your content control will render the string surrounded by a red border.
But as you anc see it is really complex to define your templates in this way.
The only scenario where i could imagine this approache is for some kind of procedurally generated templates.
Another way is to generate a string for the template and then load it with XamlReader:
string xaml = "<Ellipse Name=\"EllipseAdded\" Width=\"300.5\" Height=\"200\"
Fill=\"Red\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"/>";
object ellipse = XamlReader.Load(xaml);
2) I don't really see the need to generate templates in code behind. For exemple for this kind of data structure:
public class User
{
public string Name { get; set; }
public User Friend { get; set; }
}
public class RootNode
{
public string Title { get; set; }
public User User { get; set; }
public List<Node> Nodes { get; set; }
}
public class Node
{
public string Title { get; set; }
public List<SubNode> SubNodes { get; set; }
}
public class SubNode
{
public string Title { get; set; }
}
You can define this type of template:
<Window
...
Title="MainWindow" Height="350" Width="525" >
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:RootNode}" ItemsSource="{Binding Nodes}">
<StackPanel x:Name="spContainer" Orientation="Horizontal">
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding User.Friend.Friend.Name}"/>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding User}" Value="{x:Null}">
<Setter TargetName="spContainer" Property="Background" Value="Yellow"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding SubNodes}">
<TextBlock Text="{Binding Title}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:SubNode}" ItemsSource="{Binding Nodes}">
<TextBlock Text="{Binding Title}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding RootNodes}"/>
</Grid>
</Window>
As you can see you can define a template by data type, you can also use triggers to modify the behavior in specific cases, you could also use som binding converters...
3) You can bind to nested properties just like to normal ones :
<TextBlock Text="{Binding User.Friend.Friend.Name}"/>
However in some cases more than two level bindings could fail (fail to resolve or fail to update when property changes, ...)

Get .Text property from dynamically added Textbox

I am dynamically adding several textboxes to my grid in my code behind. I would like to be able to capture what the user enters into those textboxes.
I'm not quiet sure how to do this as the name of the dynamically added textbox is not available when I try to add it in my codebehind.
I want to create a querybuilder tool. This is very rudementary but basically I want to add multiple comboboxes, textboxes and buttons.
First of all, you must leave behind the traditional mentality of manipulating UI elements in code and Embrace MVVM
<Window x:Class="MiscSamples.QueryBuilderSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MiscSamples"
Title="QueryBuilderSample" Height="300" Width="300">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ComboBox ItemsSource="{Binding Operators}"
SelectedItem="{Binding Operator}"/>
<TextBox Text="{Binding Value}" Grid.Column="1"/>
<Button Content="Add" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
Code behind:
public partial class QueryBuilderSample : Window
{
public List<QueryCriteria> Criterias { get; set; }
public QueryBuilderSample()
{
InitializeComponent();
DataContext = Criterias = Enumerable.Range(0, 10).Select(x => new QueryCriteria()).ToList();
}
}
ViewModel:
public class QueryCriteria
{
public List<Operators> Operators
{
get
{
return Enum.GetValues(typeof(Operators))
.Cast<Operators>()
.ToList();
}
}
public Operators Operator { get; set; }
public string Value { get; set; }
}
public enum Operators
{
Equals,
Contains,
GreaterThan,
SmallerThan,
}
Result:
Notice that I'm not doing a single line of code to create / manipulate UI elements. Everything is done via DataBinding.
Simple code. No complex event handling stuff or anything like that.
Declarative Code. Just Simple, Simple Properties and INotifyPropertyChanged. That's the default approach to EVERYTHING in WPF.
When you insert a text box, keep a reference to it in some object. A dictionary could be a good choice. That way, you can get that reference later, and from that reference you can read its Text property.
#jeff V you can simply capture the textbox text by using the name your assigning those textboxes..
you are using tb1,tb2 as textboxes name...so you can easily get the values using

Binding on dynamically-added elements

TPTB have decided that our app must run in a single window, popping up new windows in modal mode is not allowed.
And naturally, we have a UI design that involves popping up modal dialogs all over the place.
So I added a top-level Grid to the Window. In that Grid I defined no rows or columns, so everything draws in Row 0/Column 0.
The first element in the Grid was another Grid that contained everything that was normally displayed in the Window. The second was a full-sized Border with a gray, semi-transparent Background. The rest were Borders with wide Margins and white Backgrounds, containing the various UserControls that needed to be displayed as popups. All but the first had Visibility="Collapsed".
And then, when I needed to show a popup, I'd set Visibility="Visible" on the gray background and on the appropriate UserControl. The result was a nice shadowbox effect that worked fine.
Until somebody decided that the popups needed to be able to display popups. In a non-predictable order.
The limitation of the method I had implemented, using Visibility="Collapsed" elements in a Grid was that their order was fixed. UserControlB would always be displayed on top of UserControlA, even if it was UserControlB that asked to have UserControlA displayed. And that's not acceptable.
So my next attempt was to define the various UserControls in Window.Resources, and to add them to the Grid in code:
this.masterGrid.Children.Add(this.Resources["userControlA"] as UserControlA);
And that almost works. But the bindings are all messed up.
As an example, one of the controls is supposed to bind a Property to the CurrentItem of a collection in a member object of the Window's viewmodel. When I had the control defined as an invisible item in the Grid, it worked fine. But when I defined it as a Resource, the Property was null - it was never bound.
So I tried binding it in code, after I added it to the grid:
userControlA.SetBinding(UserControlA.myProperty, new Binding()
{ Source = this.viewModel.myCollection.CurrentItem });
And that compiles and runs just fine, but I'm not binding to the right object.
The first time I display the UserControl, I see the right object bound to it. But when I close it, and move the CurrentItem in the collection to a different object, and display the UserControl again, I still see the first object bound. If I close it again, and open it a third time, then I will see the right object bound to the control.
I've checked in code, and the CurrentItem that I'm binding to is right, every time, but it only seems to take every other time.
So I tried explicitly clearing the binding, first:
BindingOperations.ClearBinding(userControlA, UserControlA.myProperty);
userControlA.SetBinding(UserControlA.myProperty, new Binding()
{ Source = this.viewModel.myCollection.CurrentItem });
But that doesn't seem to have made any difference.
In all, it feels like I'm running down a rabbit hole, chasing deeper and deeper into complexity, to solve what should be a fairly simple problem.
Does anyone have any suggestions as to:
How to get binding to work on dynamically-added elements, or
How to get arbitrarily-ordered popups to display, as shadowboxes, without using dynamically-ordered elements?
Thanks in advance.
While it seems really odd for me that you can't create new Windows, I would definitely recommend not to complicate it too much by doing unnecesary things such as storing your views in the MainWindow's resources.
It would be better if you just added new instances of these elements into an ObservableCollection:
XAML:
<Window x:Class="WpfApplication4.Window8"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="Window8" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type local:ViewModel1}">
<StackPanel Background="Green">
<TextBlock Text="This is ViewModel1!!"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModel2}">
<StackPanel Background="Blue" HorizontalAlignment="Center">
<TextBlock Text="This is ViewModel2!!"/>
<TextBlock Text="{Binding Text2}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModel3}">
<StackPanel Background="Red" VerticalAlignment="Center">
<TextBlock Text="This is ViewModel3!!"/>
<TextBlock Text="{Binding Text3}"/>
<TextBox Text="{Binding Text3}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<DockPanel>
<Button Width="100" Content="Add" Click="Add_Click" DockPanel.Dock="Top"/>
<Button Width="100" Content="Remove" Click="Remove_Click" DockPanel.Dock="Top"/>
<ListBox ItemsSource="{Binding ActiveWidgets}" SelectedItem="{Binding SelectedWidget}">
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ListBox.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter ContentSource="Content"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DockPanel>
</Window>
Code Behind:
using System.Linq;
using System.Windows;
using System.Collections.ObjectModel;
using System;
namespace WpfApplication4
{
public partial class Window8 : Window
{
private WidgetsViewModel Widgets { get; set; }
public Window8()
{
InitializeComponent();
DataContext = Widgets = new WidgetsViewModel();
}
private Random rnd = new Random();
private int lastrandom;
private void Add_Click(object sender, RoutedEventArgs e)
{
var random = rnd.Next(1, 4);
while (random == lastrandom)
{
random = rnd.Next(1, 4);
}
lastrandom = random;
switch (random)
{
case 1:
Widgets.ActiveWidgets.Add(new ViewModel1() {Text = "This is a Text"});
break;
case 2:
Widgets.ActiveWidgets.Add(new ViewModel2() { Text2 = "This is another Text" });
break;
case 3:
Widgets.ActiveWidgets.Add(new ViewModel3() { Text3 = "This is yet another Text" });
break;
}
Widgets.SelectedWidget = Widgets.ActiveWidgets.LastOrDefault();
}
private void Remove_Click(object sender, RoutedEventArgs e)
{
Widgets.ActiveWidgets.Remove(Widgets.SelectedWidget);
Widgets.SelectedWidget = Widgets.ActiveWidgets.LastOrDefault();
}
}
public class WidgetsViewModel: ViewModelBase
{
public ObservableCollection<ViewModelBase> ActiveWidgets { get; set; }
private ViewModelBase _selectedWidget;
public ViewModelBase SelectedWidget
{
get { return _selectedWidget; }
set
{
_selectedWidget = value;
NotifyPropertyChange(() => SelectedWidget);
}
}
public WidgetsViewModel()
{
ActiveWidgets = new ObservableCollection<ViewModelBase>();
}
}
public class ViewModel1: ViewModelBase
{
public string Text { get; set; }
}
public class ViewModel2: ViewModelBase
{
public string Text2 { get; set; }
}
public class ViewModel3: ViewModelBase
{
public string Text3 { get; set; }
}
}
Just copy and paste my code in a File - New - WPF Application and see the results for yourself.
Since the Grid always places the last UI Element added to it topmost, you will see that Adding items to the observablecollection makes these "different widgets" always appear on top of each other, with the topmost being the last one added.
The bottom line is, when WidgetA requests to open WidgetB, just create a new WidgetBViewModel and add it to the ActiveWidgets collection. Then, when WidgetB is no longer needed, just remove it.
Then, it's just a matter of putting your UserControls inside a proper DataTemplate for each ViewModel. I strongly suggest you keep a separate ViewModel for each of your Widgets, and if you need to share data between them, just share data between the ViewModels.
Don't attempt to do things like ListBox ItemsSource="{Binding Whatever, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}" unless you have a good reason to.
This way you no longer have to deal with Panel.ZIndex stuff. Maybe you can create a couple of attached properties to deal with things like focus and whatnot, but this approach is dead simple, and by far more performant than the Visibility and the Resources approaches.

WPF binding subcontrols to a parent control

I am trying to perform databinding, given the following case:
I have a class called "Node" that has two properties: "speed" and "pauseTime". I then have an array of Nodes.
In my XAML, I have a numeric control (labeled Node) that allows the user to switch between Nodes. There are also two subcontrols which I want to have show speed and pauseTime for the selected Node.
My question is how do I set the databinding for speed, for example, so that it shows the speed for the selected Node in the Nodes array based on the value in the Node numeric control?
I tried googling this, but am not sure what search terms to use.
I'm not sure what you mean by numeric control, but I knocked up an example of a master details control scenario.
In the XAML you have a Grid with a ListView (the master), and a TextBlock (the details):
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ListView ItemsSource="{Binding}" x:Name="masterListView">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock Grid.Row="1" Text="{Binding ElementName=masterListView, Path=SelectedItem.Speed}" />
</Grid>
The code behind looks like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Node[]
{
new Node() { Speed = 1, PauseTime = "1 Min", Name = "Item 1" },
new Node() { Speed = 2, PauseTime = "2 Mins" , Name = "Item 2" }
};
}
}
public class Node
{
public int Speed { get; set; }
public string PauseTime { get; set; }
public string Name { get; set; }
}
The child TextBlock binds to the Speed property of the Selected node. If you add IsSynchronizedWithCurrentItem="True" to the ListView, the first item will automatically be selected when the window is loaded. If you Google master details/WPF and IsSynchronizedWithCurrentItem="True" you will find more details.
It would probably also be useful to Google how to do this using MVVM- a reasonable approach is mentioned in this Stackoverflow Answer.

Padding text in listbox

var a1 = "HEL";
var a2 = "HELLO";
var a3 = "LLO";
var length = a2.Length+5;
listbox.Items.Add(a1.PadRight(length) +"End");
listbox.Items.Add(a2.PadRight(length) + "End");
listbox.Items.Add(a3.PadRight(length) + "End");
I have code like this to obviously pad all text so that the word End lines up.
The problem is I have to change the font from the wpf listbox from Segoe UI to Courier New to have this work. The rest of my app uses Segoe UI, so I think it looks weird here.
Is there any way to achieve the result with Segoe UI or maybe a similar font with correct spacing I could use, or maybe someone has some other smart solution i haven't even thought of? :-)
Thanks
edit
at the end of the day I want this to display to related items like this:
ITEM A -> ITEM B
ITEM X -> ITEM Y
ITEM C -> ITEM E
dont want to use gridview.
Feed the ListBox the two pieces of data separately, and use a data template. Here's how.
First, create a little class to represent each item you want to insert:
public class WordPair {
public string First { get; set; }
public string Second { get; set; }
}
(You probably already have a suitable class and/or collection in your application -- I assume those pairs of strings are coming from somewhere!)
Second, set your ListBox.ItemsSource to a collection of these things:
listBox.ItemsSource = new List<WordPair> {
new WordPair { First = "ITEM A", Second = "ITEM B" },
new WordPair { First = "ITEM X", Second = "ITEM Y" },
};
Again, this collection may already exist in your app.
Third, create a DataTemplate specifying the desired layout, and assign it to your ListBox.ItemTemplate:
<!-- in your Window.Resources section -->
<DataTemplate x:Key="AlignedPairs">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding First}" Grid.Column="0" />
<TextBlock Text="->" TextAlignment="Center" Grid.Column="1" />
<TextBlock Text="{Binding Second}" TextAlignment="Right" Grid.Column="2" />
</Grid>
</DataTemplate>
<ListBox Name="listBox" ItemTemplate="{StaticResource AlignedPairs}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
(I've guessed at the exact alignment you want for the items, but you can obviously tweak it.)
Note that you also need to set the HorizontalContentAlignment of the ListBoxItems to Stretch using ListBox.ItemContainerStyle. Otherwise each ListBoxItem will take up only the space it needs, resulting in all the Grid columns being minimal size and looking like a straight concatenation. Stretch makes each ListBoxItem fill the full width so the Grid columns are forced to grow accordingly.
<ListBox
x:Name="listBox" HorizontalContentAlignment="Right"/>
check it :)

Resources