Reputation: 1674
Please bear with me as I continue to struggle with WPF. I have this window which illustrates what I am trying to achieve. I have some data (Name, Value 1, Value 2) that I wish display.
XAML:
<Window x:Class="WpfApplication2.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>
<ItemsControl>
<Grid Height="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name:" FontWeight="Bold" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,0"/>
<TextBlock Text="{Binding MyName}" Grid.Column="1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Center"/>
</Grid>
<Grid Height="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Value 1:" FontWeight="Bold" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,0"/>
<TextBlock Text="{Binding MyValue1}" Grid.Column="1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Center"/>
</Grid>
<Grid Height="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Value 2:" FontWeight="Bold" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,0"/>
<TextBlock Text="{Binding MyValue2}" Grid.Column="1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Center"/>
</Grid>
</ItemsControl>
</Grid>
</Window>
As you can see each line in the window is a Grid
with two text boxes. Each definition is the same apart from the TextBlocks
text bindings. This means that if I decide to move the Name, Value 1, and Value 2 over to the left to get rid of the white space I have to update each definition.
How can I simplify the XAML such that I can avoid mindlessly updating every single Grid
?
Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string myName;
public string MyName
{
get { return myName; }
set { myName = value; }
}
private int myValue1;
public int MyValue1
{
get { return myValue1; }
set { myValue1 = value; }
}
private float myValue2;
public float MyValue2
{
get { return myValue2; }
set { myValue2 = value; }
}
public MainWindow()
{
InitializeComponent();
MyValue1 = 5;
MyName = "This is a test";
MyValue2 = 1.618f;
this.DataContext = this;
}
}
}
P.S. I've read about DataTemplate
and Styles
but I am unsure how to apply them here.
Upvotes: 0
Views: 111
Reputation: 52
Just try to use this simple example.
MainWindow.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">
<Grid>
<ItemsControl ItemsSource="{Binding Entities}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Caption}" FontWeight="Bold" TextWrapping="Wrap" />
<TextBlock Text="{Binding Value}" Grid.Column="1" TextWrapping="Wrap" Margin="10,0,0,0"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Entities = new ObservableCollection<YourEntity>()
{
new YourEntity{ Caption = "Name:", Value = "Test Name"},
new YourEntity{ Caption = "Value1:", Value = "Test Value1"},
new YourEntity{ Caption = "Value2:", Value = "Test Value2"}
};
this.DataContext = this;
}
public ICollection<YourEntity> Entities { get; private set; }
}
And a class YourEntity.cs:
public class YourEntity
{
public string Caption { get; set; }
public object Value { get; set; }
}
Upvotes: 0
Reputation: 14487
Alternatively, you also can use an LabelGrid
:
LabelGrid.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace XyWpf.Library.Controls
{
public class LabelGrid : Grid
{
public GridLength LabelColumnWidth { get; set; }
public GridLength ContentColumnWidth { get; set; }
public LabelGrid()
{
LabelColumnWidth = GridLength.Auto;
ContentColumnWidth = new GridLength(1, GridUnitType.Star);
}
public override void EndInit()
{
base.EndInit();
var children = this.Children.Cast<UIElement>().ToList();
this.Children.Clear();
this.ColumnDefinitions.Add(new ColumnDefinition() { Width = LabelColumnWidth });
this.ColumnDefinitions.Add(new ColumnDefinition() { Width = ContentColumnWidth });
for (int i = 0; i < children.Count; i++)
{
this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var child = children[i];
Grid.SetColumn(child, 1);
Grid.SetRow(child, i);
this.Children.Add(child);
var label = new Label() { Content = Element.GetLabel(child) };
Grid.SetColumn(label, 0);
Grid.SetRow(label, i);
this.Children.Add(label);
label.SetBinding(Label.VisibilityProperty, new Binding("Visibility")
{
Mode = BindingMode.OneWay,
Source = child
});
}
}
}
public partial class Element
{
public static readonly DependencyProperty LabelProperty =
DependencyProperty.RegisterAttached("Label",
typeof(string), typeof(Element), new PropertyMetadata(string.Empty));
public static object GetLabel(UIElement element)
{
return element.GetValue(LabelProperty);
}
// required
public static void SetLabel(UIElement element, string value)
{
element.SetValue(LabelProperty, value);
}
}
}
usage example :
<xy:LabelGrid>
<TextBlock xy:Element.Label="Name : "
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontWeight="Bold"
Text="{Binding Name}"
TextWrapping="Wrap" />
<TextBlock xy:Element.Label="Value 1"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontWeight="Bold"
Text="{Binding MyValue1}"
TextWrapping="Wrap" />
<TextBlock xy:Element.Label="Value 2"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontWeight="Bold"
Text="{Binding MyValue2}"
TextWrapping="Wrap" />
</xy:LabelGrid>
Upvotes: 0
Reputation: 2956
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128"/>
<ColumnDefinition Width="128"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<TextBlock Text="Name:" FontWeight="Bold" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,0" Grid.Column="0" Grid.Row="0"/>
<TextBlock Text="{Binding MyName}" Grid.Column="1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Center"/>
</Grid>
use only one grid and specify the row and column to the controls you are interested to place eg:
Grid.Column="0" Grid.Row="0"
Upvotes: 1