WPF Properties Panel similar to Visual Studio's - c#

Just wondering is their any examples or elements which can look very similar to the Properties panel used in Visual Studio? My guess the one in Visual Studio 2010 is built upon WPF, almost definitely a treeview?

Mindscape has a free one.
There is one on CodeProject.
Actipro develops a very nice one.
As does ComponentOne.

If you want to use some simple XAML, the following is visually identical to the WinForms PropertyGrid but is much easier to work with:
<Style x:Key="InnerBorder" TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Margin" Value="4" />
<Setter Property="BorderBrush" Value="#B4B0A8" />
</Style>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Main property grid area -->
<Border Style="{StaticResource InnerBorder}">
<ListBox
ItemsSource="{Binding Parameters}"
IsSynchronizedWithCurrentItem="True"
KeyboardNavigation.TabNavigation="Continue"
HorizontalContentAlignment="Stretch" BorderThickness="0">
<!-- Category grouping rows -->
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Background="#D4D0C8" FontWeight="Bold" Padding="2 2 0 4" Margin="0 0 0 3"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style>
<Setter Property="Control.Margin" Value="0 0 0 8" />
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<!-- Item container style -->
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Focusable" Value="False" />
<Setter Property="TabIndex" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<DockPanel Margin="4 0 0 0" IsKeyboardFocusWithinChanged="DockPanel_IsKeyboardFocusWithinChanged" MouseDown="DockPanel_MouseDown">
<TextBlock Name="TitleBlock" Text="{Binding DisplayName}" Width="135" />
<ContentPresenter />
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="TitleBlock" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter TargetName="TitleBlock" Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Border>
<!-- Help area -->
<Border Style="{StaticResource InnerBorder}" Grid.Row="1" DataContext="{Binding Parameters}">
<StackPanel HorizontalAlignment="Stretch" Margin="2">
<TextBlock FontWeight="Bold" Text="{Binding /DisplayName}" />
<TextBlock Text="{Binding /Description}" TextWrapping="Wrap" />
</StackPanel>
</Border>
</Grid>
And here is the code behind
private void DockPanel_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var element = (FrameworkElement)sender;
if(element.IsKeyboardFocusWithin)
{
Visual cur = element;
while(cur!=null && !(cur is ListBoxItem))
cur = (Visual)VisualTreeHelper.GetParent(cur);
((ListBoxItem)cur).IsSelected = true;
}
}
private void DockPanel_MouseDown(object sender, MouseEventArgs e)
{
((FrameworkElement)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}
private void InitializeView()
{
var view = CollectionViewSource.GetDefaultView(Parameters);
if(view.GroupDescriptions.Count==0)
view.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
if(view.SortDescriptions.Count==0)
{
view.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending));
view.SortDescriptions.Add(new SortDescription("DisplayName", ListSortDirection.Ascending));
}
}
The reason this property grid is nicer to work with in WPF is that you can add any kind of object to the Parameters collection as long as it has a Category, DisplayName, and Description.
If you want to use it to actually display the properties of a specific object, it only takes a few lines to load up the Parameters collection with the appropriate objects.

Related

How can I add something to my custom listbox?

I made a custom listbox but when I push the button show every language nothing is showing. How can I fix this. When I delete the listbox style it just works fine. It's all in C#.
I hope you can help me.
greetings
Elias
<ListBox x:Name="lsbResultaatTaal"
Foreground="Black"
FontSize="15"
Grid.Row="1"
Margin="528,56,0,0"
Height="450"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="233">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{d:SampleData ItemCount=5}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Background" Value="Gray"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<Border Width="230" Height="450"
CornerRadius="9"
BorderThickness="1"
BorderBrush="Black"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
You can set style in resources
<Window.Resources>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray" />
<!--
Why you choose same background color when hover listbox
Maybe same color your background and foreground
-->
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
OR
Can you try below changes:
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding YourProp}" />

How to show a value which is not bound by the CategoryPath or ValuePath inside the Telerik's RadCartesianChart's Tooltip?

I'm working with a telerik RadCartesianChart. And I'm supposed to show a tooltip which conveys the information about the series inide the chart (such as the date, the value, the title of the series). I was able to show the date and value which were already bound in the CategoryPath and the ValuePath of the chart respectively. But I have no clue how to show the title of the series which belongs to the same data source but not bound by either the CategoryPath or the ValuePath.
Below is what I have done so far.
<telerik:RadCartesianChart x:Name="chart" Margin="0,10,0,36" Width="auto" Grid.RowSpan="2">
<telerik:RadCartesianChart.Behaviors>
<telerik:ChartTooltipBehavior HorizontalOffset="-11" VerticalOffset="-50" />
</telerik:RadCartesianChart.Behaviors>
<telerik:RadCartesianChart.TooltipTemplate>
<DataTemplate>
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1" Padding="5" CornerRadius="3">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Category}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Value, StringFormat=\{0:N2\}}" />
</StackPanel>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</telerik:RadCartesianChart.TooltipTemplate>
<telerik:RadCartesianChart.HorizontalAxis>
<telerik:DateTimeCategoricalAxis
x:Name="datetimeAxis"
LabelFitMode="MultiLine"
LabelFormat="{Binding Tab.CurrentPoC.LabelFormat}"
LabelInterval="1"
LabelOffset="0"
LabelRotationAngle="270"
LabelStyle="{DynamicResource LabelStyle}"
LastLabelVisibility="Visible"
LineDashArray="1 1"
LineStroke="{DynamicResource CouleurTexte}"
LineThickness="1"
MajorTickInterval="1"
MajorTickLength="1"
PlotMode="OnTicks"
SmartLabelsMode="SmartStep"
TickThickness="5"
ZIndex="0" Height="5" />
</telerik:RadCartesianChart.HorizontalAxis>
<telerik:RadCartesianChart.VerticalAxis>
<telerik:LinearAxis Foreground="White" LastLabelVisibility="Visible" HorizontalLocation="Right"/>
</telerik:RadCartesianChart.VerticalAxis>
<telerik:RadCartesianChart.Grid>
<telerik:CartesianChartGrid MajorLinesVisibility="Y" />
</telerik:RadCartesianChart.Grid>
<telerik:RadCartesianChart.Resources>
<Style x:Key="AxisLineStyle" TargetType="{x:Type telerik:LinearAxis}" >
<Setter Property="Foreground" Value="{Binding ColorName, Mode=TwoWay, Converter={StaticResource NVarToBrushConverter}}"/>
<Setter Property="Background" Value="{Binding ColorName, Mode=TwoWay, Converter={StaticResource NVarToBrushConverter}}"/>
</Style>
<DataTemplate x:Key="ellipseTemplate">
<Ellipse Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}"/>
</DataTemplate>
<DataTemplate x:Key="rectangleTemplate">
<Rectangle Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>
<DataTemplate x:Key="triangleTemplate">
<Polygon Points="10,5 5,10 15,10 10,3" Stroke="GreenYellow" StrokeThickness="2" Fill="{Binding Converter={StaticResource PaletteConverter}}"/>
</DataTemplate>
<!--<DataTemplate x:Key="+Template">
<Rectangle Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>
<DataTemplate x:Key="xTemplate">
<Rectangle Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>-->
<Style TargetType="telerik:LineSeries" BasedOn="{StaticResource LineSeriesStyle}">
<Setter Property="LegendSettings" Value="{Binding Converter={StaticResource ChartViewLegendSettingsValueConverter}}"/>
<Setter Property="ShowLabels" Value="False"/>
<Setter Property="Stroke" Value="{Binding ColorName, Mode=TwoWay, Converter={StaticResource NVarToBrushConverter}}"/>
<Setter Property="VerticalAxis">
<Setter.Value>
<telerik:LinearAxis ElementBrush="{Binding Tab.CurrentPoC.LineSeriesColor}" HorizontalLocation="Left"/>
</Setter.Value>
</Setter>
<Setter Property="PointTemplateSelector" Value="{StaticResource templateSelector}"/>
</Style>
<Style TargetType="telerik:BarSeries" BasedOn="{StaticResource BarSeriesStyle}">
<Setter Property="CombineMode" Value="Stack"/>
<Setter Property="LegendSettings" Value="{Binding Converter={StaticResource ChartViewLegendSettingsValueConverter}}"/>
<Setter Property="ShowLabels" Value="False"/>
<Setter Property="VerticalAxis">
<Setter.Value>
<telerik:LinearAxis ElementBrush="Gray" HorizontalLocation="Right"/>
</Setter.Value>
</Setter>
<Setter Property="PointTemplate">
<Setter.Value>
<DataTemplate>
<Rectangle Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="telerik:PointSeries" BasedOn="{StaticResource PointSeriesStyle}">
<Setter Property="LegendSettings" Value="{Binding Converter={StaticResource ChartViewLegendSettingsValueConverter}}"/>
<Setter Property="ShowLabels" Value="False"/>
<Setter Property="Width" Value="15"/>
<Setter Property="Height" Value="15"/>
<Setter Property="VerticalAxis">
<Setter.Value>
<telerik:LinearAxis ElementBrush="{Binding Tab.CurrentPoC.PointSeriesColor}" HorizontalLocation="Left" />
<!--Style="{DynamicResource AxisLineStyle}"-->
</Setter.Value>
</Setter>
<Setter Property="PointTemplateSelector" Value="{StaticResource templateSelector}"/>
</Style>
</telerik:RadCartesianChart.Resources>
<telerik:RadCartesianChart.SeriesProvider>
<telerik:ChartSeriesProvider Source="{Binding Tab.CurrentPoC.GraphsToDisplay, Mode=TwoWay}">
<telerik:ChartSeriesProvider.SeriesDescriptors>
<telerik:CategoricalSeriesDescriptor x:Name="CatSeries" CategoryPath="TimeStampX" ValuePath="ValueY" ItemsSourcePath="Data" TypePath="SerieType"/>
</telerik:ChartSeriesProvider.SeriesDescriptors>
</telerik:ChartSeriesProvider>
</telerik:RadCartesianChart.SeriesProvider>
</telerik:RadCartesianChart>
To achieve your requirement, you can use the Presenter property of the DataPoint object.
The DataPoint object is the data context passed to the TooltipTemplate.
The Presenter is a property of DataPoint which holds a reference to the series object that hosts the concrete data point.
<telerik:RadCartesianChart.TooltipTemplate>
<DataTemplate>
<TextBlock Text="{Binding Presenter.DataContext.MySeriesNameProperty}" />
</DataTemplate>
</telerik:RadCartesianChart.TooltipTemplate>
You can read a bit more about the DataPoint class in the RadChartView documentation.
I got it working by adding a new property called LegendName to the data source object. And changed the binding path like this <TextBlock Text="{Binding Path=DataItem.LegendName}"/>. Not sure whether this is the proper way but it's working as intended.

Unable to resize StackPanel when IDataErrorInfo is triggered

When a TextBox element has an error The custom adorner doesn't resize the StackPanel the Textbox control lies in:
Using DockPanel.Bottom causes the adorner to overlap on the Textbox below.
The code I shamelessly lifted off http://hirenkhirsaria.blogspot.ie/2013/05/wpf-input-validation-using-mvvm.html:
<ControlTemplate.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
</ControlTemplate.Resources>
<DockPanel LastChildFill="true">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Border>
<AdornedElementPlaceholder Name="customAdorner">
<Border BorderBrush="#DC000C" BorderThickness="1.3" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
Sure, I could use Z Index but I don't like it.
Is there a way to cause the StackPanel to resize on error?
I was thinking of adding a ContentTemplate after each Textbox control:
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
The ContentTemplate generates an error info DataTemplate which I believe should cause the StackPanel to resize.
But I can't figure out how the binding to (Validation.Errors)[0].ErrorContent} should be done.
My terrible attempt:
<UserControl.Resources>
<DataTemplate x:Key="errorinfo">
<TextBlock>Hello World</TextBlock>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<StackPanel>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
</StackPanel>
<ContentControl >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=name, Path=(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ElementName=name, Path=(Validation.Errors)[0].ErrorContent}"> </TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
I can't reuse the datatemplate though!
My question is similar to: WPF- Validation -The validation error message goes behind the other controls because of AdornerDecorator
I just want a different solution.
Any ideas? Thanks
Adorner layers sit separate from the main rendering layers in WPF. A good way to think of an Adorner is simply as a graphical overlay layer which encompasses the shape of the Control it's element tags surround (similar to the behaviour of a Border for example).
You don't need a separate AdornerDecorator for every Control. This means the ideal solution would be to add the AdornerDecorator at the highest level possible such as your Window so that you are always guaranteed an Adorner scope.
I can't believe it! Figured it out myself :D
<UserControl.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
<DataTemplate x:Key="errortemplate">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding Path=(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
<Style x:Key="ContentControlErrorTemplate" TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
<ContentControl Style="{StaticResource ContentControlErrorTemplate}">
</ContentControl>
</StackPanel>
If you have ideas to improve it please let me know. I'm not sure how efficient it is but it works.

Applying a Custom Template for TextBox Header

I am developing a windows phone app and my requirements include to use a specific color theme and not use the default theme (Light/Dark/etc.) of the phone.
I'm stuck at formatting/templating the headers of textboxes. The following code in the app.xaml is not working:
<DataTemplate x:Key="HeaderTemplate">
<TextBlock Text="{Binding}" Foreground="Black"/>
</DataTemplate>
<Style TargetType="TextBox">
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate" Value="{StaticResource HeaderTemplate}"/>
</Style>
Is there either a way just to configure the theme used or a way to implement the template for the headers?
If you need to implement a Template on a Page
<Page.Resources>
<Style TargetType="TextBox">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding}" Foreground="Red" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel>
<TextBox x:Name="TextBox" Width="300" Height="80"
Margin="20" Header="Headline"/>
<TextBox x:Name="TextBox2" Width="300" Height="80"
Margin="20" Header="Headline2"/>
</StackPanel>
or if you want the Style to apply to certain TextBox give it a Key
<Style TargetType="TextBox" x:Key="MyTextBoxStyle">
and apply to relevant TextBox
<TextBox x:Name="TextBox2" Width="300" Height="80"
Margin="20" Header="Headline2"
Style="{StaticResource MyTextBoxStyle}"/>}"/>
Hope that helps
It is really strange I tested the following:
<Application.Resources>
<Style TargetType="TextBox" >
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="Red" Text="testing"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="DT1">
<TextBlock Foreground="Green" Text="testing"/>
</DataTemplate>
<Style TargetType="TextBox" x:Key="TextBoxStyle2">
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate" Value="{StaticResource DT1}"/>
</Style>
</Application.Resources>
and in the mainpage
<Grid>
<TextBox Text="testing"/>
<TextBox Margin="0,100,0,0" Style="{StaticResource TextBoxStyle2}" Text="testing"/>
</Grid>
And it works, so I think the content from the binding is empty and appears not be working.

Setting an element's width to the rest of container

OK this is stupid! I'm confused. I have this xaml:
<StackPanel Style="{DynamicResource FormPanel}">
<StackPanel>
<Label Content="{DynamicResource Label_FirstName}"
Target="{Binding ElementName=FirstName}"/>
<TextBox x:Name="FirstName" />
</StackPanel>
<StackPanel>
<Label Content="{DynamicResource Label_LastName}"
Target="{Binding ElementName=LastName}"/>
<TextBox x:Name="LastName" />
</StackPanel>
<!-- and so one... for each row, I have a StackPanel and a Label and Textbox in it -->
</StackPanel>
and this style:
<Style x:Key="FormPanel" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Vertical"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Style.Resources>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="10"/>
<Style.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Width" Value="140"/>
</Style>
<Style TargetType="{x:Type TextBox}">
<!-- this line doesn't affect -->
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</Style.Resources>
</Style>
</Style.Resources>
</Style>
I want to set the TextBox.Width to the rest of container's (StackPanel) width. It seems in this case, HorizontalAlignment = Stretch not works. Have you any idea?
StackPanel only allocates space required to child elements than what's available. What you need is a DockPanel.
have a look at This for some detailed explanations on the same topic.
You can modify your code to something like:
<Style x:Key="FormPanel"
TargetType="{x:Type StackPanel}">
<Setter Property="Orientation"
Value="Vertical" />
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Style.Resources>
<Style TargetType="{x:Type DockPanel}">
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Setter Property="Margin"
Value="10" />
<Setter Property="LastChildFill"
Value="True" />
<Style.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Width"
Value="140" />
</Style>
</Style.Resources>
</Style>
</Style.Resources>
</Style>
usage:
<StackPanel Style="{DynamicResource FormPanel}">
<DockPanel>
<Label Content="{DynamicResource Label_FirstName}"
Target="{Binding ElementName=FirstName}" />
<TextBox x:Name="FirstName" />
</DockPanel>
<DockPanel>
<Label Content="{DynamicResource Label_LastName}"
Target="{Binding ElementName=LastName}" />
<TextBox x:Name="LastName" />
</DockPanel>
<!-- and so one... for each row, I have a StackPanel and a Label and Textbox in it -->
</StackPanel>
Misc:
in your case I'd probably not do this though. if your use case is to have N rows with each having 2 columns where second column stretches to use all remaining space, rather than have a StackPanel with a bunch of DockPanel's inside it per row, you can do it all with just using a Grid.
something like:
<Grid Margin="5">
<Grid.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Margin"
Value="5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin"
Value="5" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Grid.Column="0"
Content="{DynamicResource Label_FirstName}"
Target="{Binding ElementName=FirstName}" />
<TextBox x:Name="FirstName"
Grid.Row="0"
Grid.Column="1" />
<Label Grid.Row="1"
Grid.Column="0"
Content="{DynamicResource Label_LastName}"
Target="{Binding ElementName=LastName}" />
<TextBox x:Name="LastName"
Grid.Row="1"
Grid.Column="1" />
</Grid>
would give you the same output with only 1 layout container used.
StackPanel will only be as big as its contents.
I recommend you replace the inner StackPanel with DockPanel. The last child of DockPanel will fill available space (unless you explicitly override that behavior).

Categories