How to make the ListBox , depending on the size of the window, decide how many lines to display information for?

Suppose there is such a xaml :

 <ListBox> <ListBox.ItemsPanel> <ItemsPanelTemplate> <UniformGrid IsItemsHost="True" Rows="2"></UniformGrid> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> 

If the window height is 500px so that the UniformGrid displayed in 2 lines, and if it is more than 700px then in 3 . How to implement this?

PS I heard something about VisualState and it seems to me that they could be used in this situation, but I did not find a normal example.

  • Through code-behind? - VladD
  • @VladD, Is it impossible in xaml ? - Lightness
  • Let's try, moment. The trigger should roll, in theory. - VladD
  • OK question. What should be the value of Rows if the window height is less than 500? If from 500 to 700? You only have exactly 500 and more than 700 in the question. - VladD
  • @VladD, I just wrote this for an example, I understand the main idea of ​​implementation. Suppose up to 500 will be 1, from 500 to 700 will be 2, and more than 700 will be 3. - Lightness

1 answer 1

Absolutely no code behind, probably will not work.

A simple solution is to calculate the logic for converting the height of the window to the number of lines through the converter:

 class WindowHeightToRowsConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var height = (double)value; if (height < 500.0) return 1; else if (height < 700) return 2; else return 3; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } 

With this, you can make a simple binding:

 <Window x:Class="..." ... Width="525" Name="Root"> <Window.Resources> <local:WindowHeightToRowsConverter x:Key="H2R"/> </Window.Resources> <Grid> <ListBox ItemsSource="..."> <ListBox.ItemsPanel> <ItemsPanelTemplate> <UniformGrid IsItemsHost="True" Rows="{Binding ActualHeight, ElementName=Root, Converter={StaticResource H2R}}"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </Grid> </Window> 

The disadvantage of this solution is that the WindowHeightToRowsConverter class WindowHeightToRowsConverter very specific and difficult to reuse. A more complex, but potentially reusable solution, for example, is.

Put comparing converters:

 class LessThanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return (double)value < (double)parameter; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } class GreaterOrEqConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return (double)value >= (double)parameter; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } 

Now, for convenience, specifying constants in the code here is such a thing:

 public class DoubleExtension : MarkupExtension { public DoubleExtension(double value) { Value = value; } public double Value { get; set; } public override object ProvideValue(IServiceProvider sp) { return Value; } } 

We write the following XAML:

 <Window x:Class="..." xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:local="..." ... Name="Root"> <Window.Resources> <local:LessThanConverter x:Key="LT"/> <local:GreaterOrEqConverter x:Key="GE"/> </Window.Resources> 
 <UniformGrid IsItemsHost="True"> <UniformGrid.Style> <Style TargetType="UniformGrid"> <Setter Property="Rows" Value="1"/> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <!-- если высота >= 500... --> <Condition Binding="{Binding ActualHeight, ElementName=Root, Converter={StaticResource GE}, ConverterParameter={local:Double 500}}" Value="True"/> <!-- и < 700... --> <Condition Binding="{Binding ActualHeight, ElementName=Root, Converter={StaticResource LT}, ConverterParameter={local:Double 700}}" Value="True"/> </MultiDataTrigger.Conditions> <!-- то Rows = 2 --> <Setter Property="Rows" Value="2"/> </MultiDataTrigger> <MultiDataTrigger> <MultiDataTrigger.Conditions> <!-- если высота >= 700... --> <Condition Binding="{Binding ActualHeight, ElementName=Root, Converter={StaticResource GE}, ConverterParameter={local:Double 700}}" Value="True"/> </MultiDataTrigger.Conditions> <!-- то Rows = 3 --> <Setter Property="Rows" Value="3"/> </MultiDataTrigger> </Style.Triggers> </Style> </UniformGrid.Style> </UniformGrid> 

This way you can combine simple conditions into complex ones.

( local:Double works with DoubleExtension .)

  • Immediately saw several new things: MarkupExtension and Condition . Everything works, thank you very much! - Lightness
  • @Lightness: Please! Glad it came in handy! - VladD