Resizeable multiple TextBoxes - c#

I'm going to create some program that resizeable (with drag) multiple Textboxes.
But, I don't know how to build this layout. Is there know how to create drag layout?

It's not entirely clear what your exact specification is here. But the drawing makes it look like you want some cells within the grid to have grab handles for varying width, while others do not. For this purpose, you should be able to use the GridSplitter object.
For example:
<Window x:Class="TestSO36334781GridSplitter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Border BorderBrush="Black" BorderThickness="1">
<Grid>
<Grid.Resources>
<p:Style TargetType="GridSplitter">
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Width" Value="5"/>
<Setter Property="Height" Value="10"/>
<Setter Property="Background" Value="Black"/>
<!-- Offset the splitter visually so it's centered over the gridline -->
<Setter Property="RenderTransform">
<Setter.Value>
<TranslateTransform X="2.5" Y="0"/>
</Setter.Value>
</Setter>
</p:Style>
<p:Style TargetType="TextBox">
<Setter Property="Height" Value="30"/>
</p:Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Label1" Grid.Column="0"/>
<TextBlock Text="Label1" Grid.Column="1"/>
<TextBlock Text="Label1" Grid.Column="2"/>
<TextBox Grid.Row="1" Grid.Column="0"/>
<TextBox Grid.Row="1" Grid.Column="1"/>
<TextBox Grid.Row="1" Grid.Column="2"/>
<GridSplitter Grid.Row="1" Grid.Column="0"/>
<GridSplitter Grid.Row="1" Grid.Column="1"/>
<TextBox Grid.Row="2" Grid.ColumnSpan="3" Text="A wide textbox here"/>
</Grid>
</Border>
</StackPanel>
</Window>
The above shows a grid with three TextBox controls in the middle row, the widths of which can be modified by the user by dragging the GridSplitter between each of them. The labels above them (i.e. the TextBlock objects) are moved/resized as well, as they share the same column with each respective TextBox.
A fourth TextBox is shown, spanning three columns in the last row, to show how you can still have other grid elements independent of the splitters. I assume you can modify the basic idea to suit your specific needs.
Note that it's important you provide your specific formatting for the splitter objects, and that they appear after the controls they share grid elements with, so that they are above those controls in the z-order.
See also this Stack Overflow question: WPF user controlled grid column width
Addendum:
As hinted at in the (now deleted) comments by Joey, it is possible to place splitter controls without them having to share the cell with (and possibly obscuring) other elements in the grid. The following XAML snippet (i.e. just the Grid element) shows how that would work:
<Grid>
<Grid.Resources>
<p:Style TargetType="GridSplitter">
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Width" Value="5"/>
<Setter Property="Height" Value="10"/>
<Setter Property="Background" Value="Black"/>
</p:Style>
<p:Style TargetType="TextBox">
<Setter Property="Height" Value="30"/>
</p:Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Label1" Grid.Column="0"/>
<TextBlock Text="Label1" Grid.Column="2"/>
<TextBlock Text="Label1" Grid.Column="4"/>
<TextBox Grid.Row="1" Grid.Column="0"/>
<TextBox Grid.Row="1" Grid.Column="2"/>
<TextBox Grid.Row="1" Grid.Column="4"/>
<GridSplitter Grid.Row="1" Grid.Column="1" ResizeBehavior="PreviousAndNext"/>
<GridSplitter Grid.Row="1" Grid.Column="3" ResizeBehavior="PreviousAndNext"/>
<TextBox Grid.Row="2" Grid.ColumnSpan="5" Text="A wide textbox here"/>
</Grid>
The above eliminates the need for the RenderTransform, as each GridSplitter winds up centered in its own column. The ResizeBehavior is set to PreviousAndNext, so that dragging the splitter affects not the width of the column in which the splitter is contained, but instead the widths of the columns immediately before and after it.
It's possible that you could apply a DataGrid control in this scenario and get it to do what you want. But there's nothing in your question that suggests to me you need the full feature set of a DataGrid, or even that you'll be happy with some of the constraints that would involve (such as the way headings are formatted, and whether you can include other fixed-width elements in the layout).

Related

WPF Panel where only one item is visible at a time (alternative to QML's StackLayout)?

I have several controls and I want to show them only one at a time.
In QML there is a type StackLayout which does that. But I haven't found a similar control in WPF.
I want to achieve the following:
<controls:StackLayout ControlIndex="{Binding CurrentlyVisibleControlIndex}">
<controls:MyCustomControl1 />
<controls:MyCustomControl2 />
<TextBlock Text="Some text" />
<Grid/>
</controls:StackLayout>
Then, from my ViewModel I want to dynamically change which control is shown.
Answers:
Direct answer to my question
Better way of solving my problem
In this case, I would go with a ContentControl templated based on the type of content you give it in your view model (rather than based on index). As the property changes, the appropriate template will be selected and displayed.
XAML
Resources define data templates for each kind of content in the control
<Window.Resources>
<DataTemplate DataType="{x:Type local:ContentXyz}">
<controls:ControlXyz/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ContentAbc}">
<controls:ControlAbc/>
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding Content}"/>
ViewModel
The Content property holds the view model for the active control. When user actions or data changes require to display a different control, set it to the appropriate view model.
public IContent Content
{
get => this.content;
set => this.SetProperty(ref this.content, value);
}
And viewmodel classes for your inner user controls need to implement IContent (which is just a marker interface to describe the view model can be used in this place).
More
Also, frameworks like Prism help you compose views in more complex ways, giving you tools like automatic view discovery - see their documentation for more.
But, I'm afraid that "abusing" ListBox for achieving my goal is not a good idea, because ListBox handles "Ctrl+LeftMouseCLick" which will deselect the item.
The ListBox needs to be hidden. It will not render.
Only its SelecteItem will be rendered.
Example for explanation:
<Window x:Class="StackLayout.StackLayoutWindow"
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:StackLayout"
mc:Ignorable="d"
Title="StackLayoutWindow" Height="450" Width="800">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Enter the index:" Margin="5"/>
<TextBox x:Name="textBox" Grid.Column="1" Text="1" Margin="5"
HorizontalContentAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Selected Item:" Margin="5" VerticalAlignment="Center"/>
<ListBox x:Name="listBox"
SelectedIndex="{Binding Text, ElementName=textBox, Mode=OneWay}"
Visibility="Collapsed">
<TextBlock Text="TextBlock" FontSize="20"/>
<Button Content="Click me!" Padding="15 5"/>
<Border Background="Blue" Width="100" Height="100"/>
<Label Content="Label" BorderBrush="SkyBlue" BorderThickness="5"/>
</ListBox>
<ContentPresenter Grid.Row="1" Grid.Column="1"
Content="{Binding SelectedItem, ElementName=listBox}"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</Window>
Do you know if it is possible to create a custom user control which will contain the list and ContentPresenter so it can be used in the way I specified in my question?
In this case (as far as I understood the task), it makes no sense.
It is enough to override the default ListBox template.
In the example, to shorten the code, the template is specified in the Window resources.
But it is better to transfer it to the dictionary and connect it to the App.
<Window x:Class="StackLayout.StackLayoutTemplateWindow"
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:StackLayout"
mc:Ignorable="d"
Title="StackLayoutTemplateWindow" Height="450" Width="800">
<FrameworkElement.Resources>
<SolidColorBrush x:Key="ListBox.Static.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Static.Border" Color="#FFABADB3"/>
<SolidColorBrush x:Key="ListBox.Disabled.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Disabled.Border" Color="#FFD9D9D9"/>
<Style x:Key="ListBoxStyle.StackLayout" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{StaticResource ListBox.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBox.Static.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
<!--<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>-->
<ContentPresenter Content="{TemplateBinding SelectedItem}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource ListBox.Disabled.Border}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</FrameworkElement.Resources>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Enter the index:" Margin="5"/>
<TextBox x:Name="textBox" Grid.Column="1" Text="1" Margin="5"
HorizontalContentAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Selected Item:" Margin="5" VerticalAlignment="Center"/>
<ListBox x:Name="listBox"
SelectedIndex="{Binding Text, ElementName=textBox, Mode=OneWay}"
Style="{DynamicResource ListBoxStyle.StackLayout}"
Grid.Row="1" Grid.Column="1"
VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="TextBlock" FontSize="20"/>
<Button Content="Click me!" Padding="15 5"/>
<Border Background="Blue" Width="100" Height="100"/>
<Label Content="Label" BorderBrush="SkyBlue" BorderThickness="5"/>
</ListBox>
</Grid>
</Window>
Optionally, you can easily create a Custom Control from the ListBox with this template.
Although I do not see the point in this.
Thanks to #EldHasp's answer I have found a much simpler solution:
<ListBox x:Class="MyProject.StackLayout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<ContentPresenter Content="{TemplateBinding SelectedItem}"/>
</ControlTemplate>
</ListBox.Template>
</ListBox>
And it can be used in the following way:
<controls:StackLayout SelectedIndex="{Binding CurrentlyVisibleControlIndex}">
<controls:MyCustomControl1 />
<controls:MyCustomControl2 />
<TextBlock Text="Some text" />
<Grid/>
</controls:StackLayout>
By the way, using the way you have proposed I have found that it is possible to implement the StackLayout much simpler
You can think of many options for implementation.
WPF is a very flexible tool.
And the task itself is relatively simple.
Here's an example of a Sharpe implementation:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace StackLayout
{
public class StackLayout : ListBox
{
public StackLayout()
=> Loaded += OnStackLayoutLoaded;
public static void OnStackLayoutLoaded(object sender, RoutedEventArgs e)
{
ListBox listBox = (ListBox)sender;
Border border = (Border)VisualTreeHelper.GetChild(listBox, 0);
ContentPresenter presenter = new ContentPresenter();
Binding snapsToDevicePixelsBinding = new Binding()
{
Path = new PropertyPath(SnapsToDevicePixelsProperty),
Source = listBox
};
Binding selectedItemBinding = new Binding()
{
Path = new PropertyPath(SelectedItemProperty),
Source = listBox
};
presenter.SetBinding(SnapsToDevicePixelsProperty, snapsToDevicePixelsBinding);
presenter.SetBinding(ContentPresenter.ContentProperty, selectedItemBinding);
border.Child = presenter;
}
}
}
In my example, the default ListBox border is preserved, but if desired, you can also remove it.
BUT once again I would like to draw your attention to the fact that you have most likely chosen the wrong path for the realization of your task as a whole.

XAML GridRow doesn't scale automatically when ErrorTemplate is displayed

I have a XAML window with a TextBox, and this TextBox has an ErrorTemplate.
The ErrorTemplate is shown below, and as you can see, I have an AdornedElementPlaceholder, followed by a textbox whose Text field is bound to the ErrorContent:
<ControlTemplate x:Key="ValidationErrorTemplateTextBlock" TargetType="{x:Type Control}">
<Border BorderBrush="Red" BorderThickness="1">
<StackPanel Orientation="Vertical">
<AdornedElementPlaceholder Name="AdornedElementPlaceholder" />
<TextBlock Text="{Binding ElementName=AdornedElementPlaceholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
FontSize="10"
Background="Red"
Foreground="White"
Padding="2" />
</StackPanel>
</Border>
</ControlTemplate>
<TextBox IsEnabled="{Binding SendMessage}"
Text="{Binding AutoMessageSubject, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource StyleBase}"
Validation.ErrorTemplate="{StaticResource ValidationErrorTemplateTextBlock}"
HorizontalAlignment="Stretch"
Grid.Row="3"
Grid.Column="1"
Grid.ColumnSpan="2" />
This works fine, except for one thing: the TextBox is inside a GridRow, with a Height="Auto". The row scales itself based on the textbox, but when the ErrorTemplate appears, with an extra TextBox on the bottom - the GridRow doesn't scale up to contain the new TextBox, and the new TextBox overlaps the elements below it.
How can I solve this?
Validation.ErrorTemplate: Gets or sets the ControlTemplate used to generate validation error feedback on the adorner layer.
This means that if you use Validation.ErrorTemplate, the validation errors are displayed on the layer above usual content, so the "second" TextBlock is displayed over the grid, not within the grid cell.
I would implement INotifyDataErrorInfo instead of semi-obsolete IDataErrorInfo, use a custom textbox style, and bind the visibility of the second TextBlock to HasErrors property. The example below uses a ToolTip instead of the second TextBlock:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<ItemsControl DisplayMemberPath="ErrorContent" ItemsSource="{Binding Path=(Validation.Errors)}" />
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
You might want to try adding Row/Column Definitions:
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

Create a full size WPF grid [duplicate]

This question already has answers here:
Autosizing a grid column to take up remaining space in parent
(2 answers)
Closed 7 years ago.
I am trying to fit a wpf grid having 4 cells to be all the time full sized on the screen, having the content of the cells equally split, but i am having problems doing it... This is the code:
<StackPanel x:Name="MainStackPanel" HorizontalAlignment="Center" Orientation="Vertical">
<StackPanel.Resources>
<Style TargetType="Rectangle">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Height" Value="Auto"/>
</Style>
</StackPanel.Resources>
<Grid x:Name="Control1" HorizontalAlignment="Center" Height="150">
<Grid.Resources>
<Style TargetType="Rectangle">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Height" Value="Auto"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle Fill="Red" Grid.Row="0" Grid.Column="1"/>
<Rectangle Fill="Blue" Grid.Row="0" Grid.Column="2"/>
<Rectangle Fill="Green" Grid.Row="1" Grid.Column="2"/>
<Rectangle Fill="Yellow" Grid.Row="1" Grid.Column="1"/>
</Grid>
</StackPanel>
Please let me know how should i get this working... or what i am doing wrong...
If you want to have a grid that has four equally spaced cells then you could do something like this.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
This will create a 2x2 grid that will automatically resize if the screen is resized. In your example, you have your grid inside of a stack panel so it is only going to fill the size of the stack panel. If you want a grid for the entire screen, you need to put your grid as your first container and set its constraints as shown above.
You are using the 'Auto' sizing property. In this case if you want it to be equally split and take up the entire space, you'll want to use '*' for both your row and column definitions. Check out the answer that Samuel gives on this related question.

C#, WPF, Autorezise Listbox when window resize

C#, Visual Studio 2010, dot net 4, WPF, Microsoft Ribbon
I have a WPF window with the ribbon menues at the top of the window and an area below
where I try to fill with my controls however I can not get the controls to rezise with
my window.
The listbox in the below example should be fully "expanded" witin its boundaries when the window appear and its width should follow the window width when the user resize the window
(the user should not resize the controls itself) by dragging i nthe windows sides.
I tried a lot of playing around with the controls and searched the web but have not been able to
find a solution (some site indicated the usage of border would do the trick).
The Image image1 is a background image spanning over the whole "surface".
The Image image2 is a small logo picture.
<DockPanel DockPanel.Dock="Top">
<Grid DockPanel.Dock="Top" Height="526" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="2" Name="BaseGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1" />
<RowDefinition Height="60" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" HorizontalAlignment="Left" Name="image1" VerticalAlignment="Top" Source="........./el_bg.jpg" Stretch="None" />
<Grid Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" Margin="2" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Name="image2" Stretch="Fill" VerticalAlignment="Top" Source="........./shiny_rgb.png" />
<ListBox Grid.Column="2" Grid.Row="0" Name="MessageToUser" VerticalAlignment="Top" />
</Grid>
</Grid>
</DockPanel>
Regards
You're setting horizontal alignments to Left that shouldn't be set. Try this:
<DockPanel DockPanel.Dock="Top">
<Grid DockPanel.Dock="Top" Height="526" VerticalAlignment="Top" Margin="2" Name="BaseGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1" />
<RowDefinition Height="60" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" HorizontalAlignment="Left" Name="image1" VerticalAlignment="Top" Source="........./el_bg.jpg" Stretch="None" />
<Grid Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Name="image2" Stretch="Fill" VerticalAlignment="Top" Source="........./shiny_rgb.png" />
<ListBox Grid.Column="2" Grid.Row="0" Name="MessageToUser" VerticalAlignment="Top">
<ListBoxItem>One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
</ListBox>
</Grid>
</Grid>
</DockPanel>
In addition, your ListBox is in the third column of its containing Grid. If you want it to stretch across the entire window, you will need to ensure it spans all three columns:
<ListBox Grid.ColumnSpan="3" Grid.Row="0" Name="MessageToUser"
VerticalAlignment="Top">
You should read up on WPF layout - you're setting way more properties here than you need to be. Once you understand it, you'll find this thing much more intuitive. In addition, you can use a tool like Snoop to help figure out what is wrong with your layout.
Applying the following style helped me meet this requirement:
<Style x:Key="listBoxAutoFill" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd"
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="Selector.IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd"
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My requirement is more about resizing the listbox height as the window grows/shrinks but the same can be applied for width.
<ListBox Grid.Row="1" Grid.Column="0" Width="158"
ItemContainerStyle="{StaticResource listBoxAutoFill}"
ItemsSource="{Binding ListBoxItems, Mode=TwoWay}" />

Setting an initial width for an expander or listbox

In a previous question I had asked, I wanted to be able to move the gridsplitter to expand the expander which contains a list box of images so that when it expands, the images resize based on the amout of space available. With help i was able to get the resizing feature to work but the problem now is that when the program initially starts up, the images are full sized instead of thumbnail size. Is there a way to set an initial width of the expander so the images initially show up as thumbnails of about 175 pixels?
ColumnDefinitions:
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="25" Width="*" />
<ColumnDefinition MinWidth="5" Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition MinWidth="5" Width="5" />
<ColumnDefinition MinWidth="25" Width="*" />
</Grid.ColumnDefinitions>
0: Expander
1: gridsplitter
2: Text box
3: gridsplitter
4: Expander (Text box with images.)
XAML:
<GridSplitter
Name="gridSplitter2"
Width="10"
Margin="0,0,0,0"
Grid.Column="3"
IsEnabled="True"
HorizontalAlignment="Center"/>
<Expander
Style="{DynamicResource ExpanderStyle}"
Name="pictureExpander"
IsExpanded="True"
Grid.Column="4"
ExpandDirection="Left"
Collapsed="pictureExpander_Collapsed"
Expanded="pictureExpander_Expanded" >
<ListBox
Name="photoList"
ItemsSource="{Binding Source={StaticResource PhotoBin}}"
IsSynchronizedWithCurrentItem="True"
ScrollViewer.CanContentScroll="False"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Yellow" />
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="5"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Image
Name="thumbnailImage"
Source="{Binding FileLocation}"
Margin="5"
Stretch="UniformToFill"
StretchDirection="Both"
HorizontalAlignment="Stretch"
/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
I think you can play around with your ColumnDefinitions. Setting a Width on your fifth ColumnDefinition will give you a starting Width for it
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="175"/>
</Grid.ColumnDefinitions>
<!-- Your other Controls.. -->
<GridSplitter Grid.Column="3" ... />
<Expander Grid.Column="4" ... />
</Grid>
Update
I'm unable to reproduce your problem. When I set Width="175" on the fifth ColumnDefinition it starts up with this width. Uploaded my sample app here: http://www.mediafire.com/?kjc9yqgmkq6dbiq

Categories