Reputation: 119
I want to make my UI more responsable and right now I have this problem:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<DockPanel LastChildFill="True">
<StatusBar HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" DockPanel.Dock="Bottom">
<StatusBarItem>
<Ellipse Width="15" Height="15" Fill="{Binding StatusColor}"></Ellipse>
</StatusBarItem>
<StatusBarItem>
<TextBlock Text="{Binding StatusText}" ToolTip="{Binding StatusToolTip}"></TextBlock>
</StatusBarItem>
<StatusBarItem HorizontalAlignment="Right">
<TextBlock Text="{Binding StatusLastAction}"></TextBlock>
</StatusBarItem>
</StatusBar>
<Grid DockPanel.Dock="Bottom" Margin="0,0,0,10">
//
// Fields to edid data from MySelectedItem
//
</Grid>
<Grid DockPanel.Dock="Top">
<DataGrid MinHeight="150" AutoGenerateColumns="True" SelectedItem="{Binding MySelectedItem}" HorizontalAlignment="Stretch" Margin="10,10,10,0" VerticalAlignment="Stretch" ItemsSource="{Binding MyItems}" IsReadOnly="True"/>
</Grid>
</DockPanel>
</ScrollViewer>
This works like a charm until the point when the DataGrid
gets to many items. The grid doesn't create a own scrollviewer it just uses the full height from the "Main"-ScrollViewer
. (see image below - bottom-right)
Look here for wanted UI design (imgur)
black > Window
green > Scrollviewer
red > DataGrid
orange > fields to edit data
top left image (good):
DataGrid
(red) fills the available space and has a own scoll viewer if there are to many items to showtop right image (good):
ScrollViewer
(green) gets visible to show the rest (orange)bottom left image (bad):
DataGrid
doen't use the min-heightbottom right image (bad):
DataGrid
uses all needed space to show all Item
Is there a way to design the UI as shown in the top images?
Upvotes: 0
Views: 1438
Reputation: 726
I usually do not create screens so that they have an external scroll, that makes everything else complicated.
According to what you illustrated in the image, your DataGrid
should have no height greater than the height of the screen.
So what you need to do is set a size for your grid, example: 60%, 70%, 80% of the height of your screen and the rest your other information
In the solution below I leave the DataGrid
always with 80% of the height on the screen
XAML
<Window x:Class="MyApp.MainWindow"
.....
Title="MainWindow"
Name="MainWindowName"
>
<DataGrid Height="{Binding ActualHeight, ElementName=MainWindowName, Converter={StaticResource PercentConverter}}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True"
/>
Converter Class
public class PercentConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return 0;
var valor = (int)(int.Parse(value.ToString()) * 0.8); //80% of my Window Height
return valor;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var valor = (int)(int.Parse(value.ToString()) / 0.8);
return valor;
}
}
I tested with a large number of data generated in a simple loop
ViewModel (My test)
public MainViewModel()
{
MyItems = new ObservableCollection<MyData>();
for (var i = 0;i < 1000;i++)
MyItems.Add(new MyData { Id = i, Name = GenerateNames() });
}
private string GenerateNames()
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var n = _random.Next(5, 15);
return new string(Enumerable.Repeat(chars, n).Select(s => s[_random.Next(s.Length)]).ToArray());
}
resulting in the image below, and whatever the size of the window the DataGrid will be 80% of the height of it
Edit: if you do not need the external scroll, ie if it is possible to keep everything visible at the same time on the screen the best way is to leave everything with relative position, this way:
<Grid.RowDefinitions>
<RowDefinition Height="6*"/> // 6*
<RowDefinition Height="3*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 6 *, 3 *, *, Auto, <fixed value> are possible values at row height, 6 and 3 means how much of the ratio I'm adding to them -->
<Grid Grid.Row="0" >
<DataGrid AutoGenerateColumns="True"
SelectedItem="{Binding MySelectedItem}"
HorizontalAlignment="Stretch"
Margin="10,10,10,0"
VerticalAlignment="Stretch"
ItemsSource="{Binding MyItems}"
IsReadOnly="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True"
/>
</Grid>
<Grid Grid.Row="1" Margin="0,0,0,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="This is an example"/>
<Label Grid.Row="1" Content="This is an example"/>
</Grid>
<StatusBar Grid.Row="2"
HorizontalAlignment="Stretch"
Margin="0,0,0,0"
VerticalAlignment="Stretch"
DockPanel.Dock="Bottom">
<StatusBarItem>
<Ellipse Width="15" Height="15" Fill="{Binding StatusColor}"></Ellipse>
</StatusBarItem>
<StatusBarItem>
<TextBlock Text="{Binding StatusText}" ToolTip="{Binding StatusToolTip}"></TextBlock>
</StatusBarItem>
<StatusBarItem HorizontalAlignment="Right">
<TextBlock Text="{Binding StatusLastAction}"></TextBlock>
</StatusBarItem>
</StatusBar>
Upvotes: 1