WPF:ListBoxItem TextTrimming

WPF: ListBoxItem TextTrimming

我正在与 WPF 一起工作,并且我在一期中堆叠。现在我有 ListBoxListBox ItemsPanelStackPanel。当 StackPanel OrientationVertical 时,它可以正常工作!
演示:

XAML代码:

 <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>

但是我需要设置StackPanel Orientation Horizontal。当我设置 Horizo​​ntal TextBlock 时,文本没有被修剪。 有解决此问题的想法吗?

谢谢 Jamaxack!

你应该设置 TextBlock.MaxWidth 属性:

<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>

编辑:

为了实现您的目标,您应该使用 MultiValueConverter 并为每个 TextBlock 元素设置宽度:

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转换器:

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();
    }
}

我创建了自定义 Grid "AutoColumGrid"。 Demo Project

Xaml代码:

<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>

后面的代码:

        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);
            }
        }

自定义网格:

 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);
            }
        }
    }
}


谢谢 Jamshed!