WPF: how to get remaining width in a StackPanel? - wpf

Given the code below:
<Window x:Class="Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="300" Width="300">
<StackPanel Background="Yellow" Orientation="Horizontal">
<TextBlock Background="Green" Text="some text" Width="200"/>
<TextBox Width="{Binding ???}" />
<TextBlock Background="Red" Text="some text" Width="50"/>
</StackPanel>
</Window>
how do you bind second textbox's width as to fill the remaining space?
Please keep in mind I'm looking for a binding solution: I know how to do it using other layouts (like DockPanel or grid) but I'm not interested in that. Also, using ElementName is not of interest.
Thanks.

Related

Xaml and docking

I have this XAML:
<Window .....>
<DockPanel VerticalAlignment="Stretch">
<StackPanel DockPanel.Dock="Top">.....</StackPanel>
<StackPanel Height="200" DockPanel.Dock="Bottom">....</StackPanel>
</DockPanel>
</Window>
The idea is the second StackPanel to be always on the bottom of the windows and the first StackPanelto be always on the top of the window and to take any acces space (i.e. stretch to the second StackPanel), but I cannot seem to achieve this. Can anyone help me?
Try switching the position of the two StackPanels and add LastChildFill="True" to your DockPanel:
<Window .....>
<DockPanel VerticalAlignment="Stretch" LastChildFill="True">
<StackPanel Height="200" DockPanel.Dock="Bottom">....</StackPanel>
<StackPanel DockPanel.Dock="Top">.....</StackPanel>
</DockPanel>
</Window>

Dock a resizable wpf DataGrid at bottom of window

In a WPF project, I want to dock a DataGrid to the bottom of a window so that if the window resizes, I will be able to utilize more of the DataGrid. Like this:
How do I do that? All my DockPanel attempts have failed.
The current attempt is here:
<Window x:Class="Foo.SQLDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Foo.Controls"
Title="test" ResizeMode="CanResize" Width="400" Height="400">
<StackPanel Orientation="Vertical" Height="Auto" Width="Auto">
<StackPanel Orientation="Vertical">
<Label Content="SQL" HorizontalAlignment="Left"/>
<TextBox Width="377" Height="100" Name="txtSQL"/>
<Button Content="Run SQL" Click="Button_Click_1" />
</StackPanel>
<Label Content="Result" HorizontalAlignment="Left"/>
<ScrollViewer Width="Auto" Height="180" DockPanel.Dock="Right,Bottom"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<DataGrid x:Name="dataResult" />
</ScrollViewer>
</StackPanel>
</Window>
The height of the scrollviewer+datagrid will not adapt however.
First of all, using DockPanel.Dock without having a DockPanel as a parent doesn't do much...
In my example I changed your root StackPanel to a DockPanel so it will work as you want.
I also used DockPanel.LastChildFill property which makes sure the last child of the DockPanel will get all the remaining space:
<DockPanel LastChildFill="True">
<StackPanel Orientation="Vertical" DockPanel.Dock="Top">
<Label Content="SQL" HorizontalAlignment="Left"/>
<TextBox Width="377" Height="100" Name="txtSQL"/>
<Button Content="Run SQL" Click="Button_Click_1" />
</StackPanel>
<Label Content="Result" HorizontalAlignment="Left" DockPanel.Dock="Top"/>
<ScrollViewer DockPanel.Dock="Bottom,Right"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<DataGrid x:Name="dataResult" />
</ScrollViewer>
</DockPanel>
Finally, to make it really stretch on all the remaining space, I removed the Height property you set, as this blocked it from stretching.
Not sure if useful or if i understand you question the right way but have you tried this:
<DataGrid DockPanel.Dock="Right, Bottom" VerticalAlignment="Bottom" HorizontalAlignment="Right" ></DataGrid>

Why this example from Pro Silverlight 4 book doesnt work?

I am reading a Pro Silverlight 4 book (http://my.safaribooksonline.com/book/programming/csharp/9781430229797/xaml/element-to-element_binding), and I do all examples from the book. But an example from the binding chapter doesnt work for me. The slider doesnt move after I compile and run the application:
<UserControl
x:Class="SilverlightApplication14.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid
x:Name="LayoutRoot"
Background="White">
<Slider
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10"></Slider>
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
</Grid>
Dave S, is absolutely correct. You can see the Z-Index problem reversing the order of the controls (so the TextBlock is before the Slider)- it will then work because the slider will be on top of the TextBlock:
<Grid
x:Name="LayoutRoot"
Background="White">
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
<Slider
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10"></Slider>
</Grid>
You can see here that Z-Index is determined by the order of controls in the XAML.
An alternate way round this (or to demonstrate) is to specify the Z-Index attached property explicitly:
<Grid
x:Name="LayoutRoot"
Background="White">
<Slider
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10" Canvas.ZIndex="1"></Slider>
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
</Grid>
The best way to fix this is to simply make sure that the elements don't overlap each other, by putting them in different rows:
<Grid
x:Name="LayoutRoot"
Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Slider Grid.Row="1"
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10"></Slider>
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
</Grid>
In this sample, the TextBlock is in row 0 and the slider is in row 1, so they no longer overlap.
Both the Slider and the TextBlock are in the Grid in the same position (0,0). This means the TextBlock is being shown drawn directly on top of the Slider so any mouse events will always be captured by the TextBlock and not the Slider. This is implicitly implied as the TextBlock has the higher Z-Index by being defined second in the Grid. If you re-arrange the Grid and apply either Grid.Row="1" or Grid.Column="1" to the TextBlock so it is beside the Slider control you should be able to use the Slider successfully.

WPF height and scroll at listbox - imposible

To keep things simple all i am trying to do is to place a listbox and a button below it. Although it seems simple it isn't. It is not, because it is in a GRID...
The row size is star size and listbox having verticalAlign top works great all the time. The problem is that I cannot add a button below it. Having a grid with 2 rows one star height and the other auto would place the button at the bottom of the form even if listbox contents are little. Trying to set both rows auto doesn't work when resizing as no scrollbar is visible at the listbox.... Any workaround for this??
Update some code
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DockPanel >
<ListBox DockPanel.Dock="Top" Name="lbStaff" ItemsSource="{Binding}"
Grid.Row="0" VerticalAlignment="Top" BorderThickness="0"
Background="WhiteSmoke" Margin="15,10,20,30" Style="{DynamicResource
ListBoxUsers}" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource
ListBoxTest1}"></Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel Margin="5,4,5,4">
<TextBlock HorizontalAlignment="Stretch" FontSize="16"><Run
Text="{Binding Name}"/> - <Run Text="{Binding Mode=OneWay,
Path=PositionString}"/></TextBlock>
<TextBlock >Τηλέφωνο <Run Text="{Binding Phone}"/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button DockPanel.Dock="Top" Grid.Row="0" HorizontalAlignment="Right"
VerticalAlignment="Top" Margin="0,10,7,0" Style="{DynamicResource
ButtonStyleNew1}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfApplication1;component/Images/filenew1.png"
Stretch="None" VerticalAlignment="Center"></Image>
<TextBlock Margin="5,0,0,0" FontSize="16">Προσθήκη Χρήστη</TextBlock>
</StackPanel>
</Button.Content>
</Button>
</DockPanel>
</Grid>
</Grid>
What i usually do is not using rows of grid but using DockPanel you can adjust the alignments by nesting each elements. But again it totally depends on the designer how they design that using grid row or any other way. What i got from the question the following code should help you out.
but if you post some code then we can figure out where the actual problem is.
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<ListBox Height="50"/>
</DockPanel>
<DockPanel DockPanel.Dock="Bottom">
<Button Height="20" DockPanel.Dock="Top"/>
<Label/>
</DockPanel>
</DockPanel>
</Grid>
So your problem here is that you have the in the ListBox you have ScrollViewer.VerticalScrollbars=Visible that make it collapsed if you dont want scrollbars and i would suggest not to use margins more in the designing. if you still have scroll bars remove the height of the ListBox and make the window larger. It all depends upon the size of the window if you don't have the size and proper alignment. Refining your code
<Window xmlns:my="clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
x:Class="MyLightWpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
xmlns:local="clr-namespace:MyLightWpfApplication.ViewModel"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<DockPanel >
<DockPanel DockPanel.Dock="Top" Width="400" Height="200">
<ScrollViewer DockPanel.Dock="Top" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ListBox Name="lbStaff" ItemsSource="{Binding AutoCompleteData}"
BorderThickness="0"
Background="WhiteSmoke" >
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel >
<TextBlock HorizontalAlignment="Stretch" FontSize="16"><Run
Text="{Binding FirstName}"/> - <Run Text="{Binding Mode=OneWay,
Path=PositionString}"/></TextBlock>
<TextBlock >Τηλέφωνο <Run Text="{Binding LastName}"/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</DockPanel>
<DockPanel DockPanel.Dock="Bottom">
<Button DockPanel.Dock="Top" Height="30" Grid.Row="0">
<Button.Content>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="16">Προσθήκη Χρήστη</TextBlock>
</StackPanel>
</Button.Content>
</Button>
<Label/>
</DockPanel>
</DockPanel>
</Grid>
</Window>
Its all dependent on how much data you have in the ListBox. I have tried this code populating listbox with 20 rows its not showing scrollbars at all
You might try auto for both and put a MaxHeight on the ListBox but you still take a chance of pushing the button off the screen. Or put both in a ScrollViewer. Or can you live with the button on top?
I solved this problem using a dockpanel. I docked buttons at bottom and then i let listbox to fill the remaining area..(lastchildfill=true) ...
It works fine...

WPF UserControl - cannot select TextBox

I have a really simple WPF UserControl:
<UserControl x:Class="dr.SitecoreCompare.WPF.ConnectionEntry"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="connEntry"
BorderBrush="Navy" BorderThickness="1" Margin="5,0,0,5" >
<StackPanel Margin="0,10,0,0" >
<Label FontWeight="ExtraBold" Content="{Binding ElementName=connEntry, Path=Title}"></Label>
<Label Margin="0,5,0,0">Server:</Label>
<TextBox x:Name="txtServer" TabIndex="1" Text="{Binding Path=ServerName}" ></TextBox>
<Label>Database:</Label>
<TextBox x:Name="txtDatabase" TabIndex="2" Text="{Binding Path=DatabaseName}"></TextBox>
</StackPanel>
This is used twice in the same window. Now, I can select the first TextBox on both th instances of my UserControl, but the second ("txtDatabase") textbox cannot be selected, neither by tabbing or clicking. Why is this ? Am I missing something with regards to creating WPF usercontrols ?
EDIT:
DatabaseName is not readonly, it is a simple property. The XAML for the window the usercontrol is placed on looks like this:
<Window x:Class="dr.SitecoreCompare.WPF.ProjectDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:dr.SitecoreCompare.WPF"
Title="Choose project" Height="280" Width="500"
WindowStartupLocation="CenterOwner" WindowStyle="SingleBorderWindow" HorizontalAlignment="Center" ShowInTaskbar="False" ShowActivated="True" ResizeMode="NoResize" VerticalContentAlignment="Top" VerticalAlignment="Center">
<StackPanel>
<Label>Choose databases</Label>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<c:ConnectionEntry Grid.Column="0" x:Name="connMaster" Title="Master:" Padding="5" />
<c:ConnectionEntry Grid.Column="1" x:Name="connSlave" Title="Slave:" Padding="5" />
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0" >
<Button x:Name="btnCancel" Click="btnCancel_Click">Cancel</Button>
<Button x:Name="btnOK" Click="btnOK_Click">OK</Button>
</StackPanel>
</StackPanel>
</Window>
Try Mode=TwoWay in your binding. I've seen this where the initialization sets the value and the control can not set the the value.
<TextBox x:Name="txtDatabase" TabIndex="2" Text="{Binding Path=DatabaseName, Mode=TwoWay}"></TextBox>
This works in XamlPad, so I think there is something outside the code you posted that is causing the problem. Is DatabaseName readonly?

Resources