Reputation: 2460
I'm working with WPF
, and I stack in one issue. Now I have ListBox
. ListBox
ItemsPanel
is StackPanel
. When StackPanel
Orientation
is Vertical
it works correctly!
Demo:
XAML code:
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="xmlData" XPath="/records">
<x:XData>
<records xmlns="">
<entry text="Veeeeeeeeeeeeeeeeeeery looooooooooooooooooooooong text"/>
<entry text="A little bit shorter text" />
<entry text="Normal text"/>
</records>
</x:XData>
</XmlDataProvider>
</Grid.Resources>
<ListBox
ItemsSource="{Binding Source={StaticResource xmlData}, XPath=entry}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=@text}" TextTrimming="CharacterEllipsis"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
But I need to set StackPanel Orientation Horizontal
. When I'm setting Horizontal TextBlock
text is not trimming.
Any Ideas to solve this issue?
Thanks Jamaxack!
Upvotes: 0
Views: 2155
Reputation: 2460
I created custom Grid
"AutoColumGrid".
Demo Project
Xaml code:
<StackPanel>
<Button Click="Button_Click">Add</Button>
<Button Click="Button_Click_1">Remove</Button>
<ListBox Name="uiList" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<local:AutoColumnGrid/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" TextTrimming="CharacterEllipsis"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
Code behind:
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
uiList.Items.Add("Looooooooooooong text 1");
uiList.Items.Add("Normal text 2");
uiList.Items.Add("Short 3");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
uiList.Items.Add("text 4");
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (uiList.Items.Count > 0)
{
uiList.Items.RemoveAt(0);
}
}
Custom Grid:
public class AutoColumnGrid : Grid
{
protected override void OnVisualChildrenChanged(System.Windows.DependencyObject visualAdded, System.Windows.DependencyObject visualRemoved)
{
//Checking VisualAdded if it is not null than adding child to Grid
if (visualAdded != null)
{
// Getting column definition count
int columnDefinitionCount = this.ColumnDefinitions.Count;
// Getting child from last, because adds to last
var child = this.Children[columnDefinitionCount];
// Adding new ColumnDefinition
this.ColumnDefinitions.Add(new ColumnDefinition());
// Setting column to child
Grid.SetColumn(child, columnDefinitionCount);
}//Checking VisualRemoved if it is not null than child from Grid
else if (visualRemoved != null)
{
int columnDefinitionIndex = Grid.GetColumn(visualRemoved as UIElement);
this.ColumnDefinitions.RemoveAt(columnDefinitionIndex);
}
Application.Current.MainWindow.Dispatcher.BeginInvoke(new Action(SetColumnWidth));
}
/// <summary>
/// Setts Width to each column
/// if Grid content bigger than window than sets width in percent else if Grid content less than window sets to auto
/// </summary>
private void SetColumnWidth()
{
for (int index = 0; index < this.ColumnDefinitions.Count; index++)
{
var gridActualWidth = this.ActualWidth;
// Getting Grids width
this.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var gridDesiredSize = Convert.ToInt16(this.DesiredSize.Width);
//calculating nesseseryAreaPercent
var nesseseryAreaPercent = gridDesiredSize / gridActualWidth * 100;
//setting column index to child
var child = this.Children[index];
Grid.SetColumn(child, index);
// if nesseseryAreaPercent less or equal 100%, it means grid content is less than grids width and we setting to auto
if (nesseseryAreaPercent <= 100)
{
this.ColumnDefinitions[index].Width = GridLength.Auto;
}
else
{ // Else setting with persent
child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
int columnWidth = Convert.ToInt16(child.DesiredSize.Width);
this.ColumnDefinitions[index].Width = new GridLength(columnWidth, GridUnitType.Star);
}
}
}
}
Thanks Jamshed!
Upvotes: 1
Reputation: 19296
You should set TextBlock.MaxWidth
property:
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="xmlData" XPath="/records">
<x:XData>
<records xmlns="">
<entry text="Veeeeeeeeeeeeeeeeeeery looooooooooooooooooooooong text"/>
<entry text="A little bit shorter text" />
<entry text="Normal text"/>
</records>
</x:XData>
</XmlDataProvider>
</Grid.Resources>
<ListBox
ItemsSource="{Binding Source={StaticResource xmlData}, XPath=entry}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock MaxWidth="200" Text="{Binding XPath=@text}" TextTrimming="CharacterEllipsis"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
EDIT:
To achieve your goal, you should use MultiValueConverter
and set width to each TextBlock
element:
XAML:
<Window x:Class="WpfListBoxItemTextTrimming.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfListBoxItemTextTrimming">
<Window.Resources>
<local:ListBoxWidthConverter x:Key="listBoxWidthConverter"/>
</Window.Resources>
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="xmlData" XPath="/records">
<x:XData>
<records xmlns="">
<entry text="Veeeeeeeeeeeeeeeeeeery looooooooooooooooooooooong text"/>
<entry text="A little bit shorter text" />
<entry text="Normal text"/>
</records>
</x:XData>
</XmlDataProvider>
</Grid.Resources>
<ListBox x:Name="LbMBox"
ItemsSource="{Binding Source={StaticResource xmlData}, XPath=entry}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=@text}" TextTrimming="CharacterEllipsis">
<TextBlock.Width>
<MultiBinding Converter="{StaticResource listBoxWidthConverter}">
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" />
<Binding ElementName="LbMBox" Path="Items.Count" />
</MultiBinding>
</TextBlock.Width>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
ListBoxWidthConverter
converter:
public class ListBoxWidthConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values != null && values.Length == 2)
{
var actualWidth = System.Convert.ToDouble(values[0]);
var numOfItems = System.Convert.ToInt32(values[1]);
return (actualWidth / numOfItems) - 10;
}
return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Upvotes: 0