Como faço para que as colunas da grelha WPF sejam definidas com a estrela para filtrar o conteúdo?

tenho um controlo da grelha que é proporcional usando a estrela, por exemplo

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="50*" />
    <ColumnDefinition Width="100*" />
    <ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
No entanto, colocar um longo TextBlock na grelha que transborda faz com que as proporções sejam perturbadas. por exemplo

<TextBlock Text="Foo" Grid.Column="0" />
<TextBlock Text="Some long text here which overflows" Grid.Column="1" />
<TextBlock Text="Foo" Grid.Column="2" />
Isto faz com que a coluna central seja mais do dobro das outras duas. Como mantenho as proporções especificadas? É possível cortar o conteúdo?

eu pus TextTrimming="CharacterEllipsis" No TextBlocks mas sem sorte.

Editar

Crucialmente, parece que a grelha está dentro de um DataTemplate, colar o seguinte para observar o comportamento,

<!-- FallbackValue is just a quick hack to get some rows to show at design-time -->
<ListBox ItemsSource="{Binding Foo, FallbackValue=1234}"
             HorizontalContentAlignment="Stretch">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50*" />
                        <ColumnDefinition Width="100*" />
                        <ColumnDefinition Width="50*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Foo" Grid.Column="0" />
                    <TextBlock Text="Some long text here which overflows" TextTrimming="CharacterEllipsis" Grid.Column="1" />
                    <TextBlock Text="Foo"  Grid.Column="2" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

a razão pela qual isto é importante é que eu tenho outro {[8] } como um irmão do {[9] } que mostra os 'cabeçalhos' para as colunas mostradas em ListBox Como se segue,

<Grid>
    ... Headers and column definitions here
</Grid>

<ListBox ...>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                ... Matching column definitions here
            </Grid>
        </DateTemplate>
    </ListBox.ItemTemplate>
</ListBox>
Por isso, é importante que as colunas coincidam.

tentei ligar o ColumnDefinitions dentro do DataTemplate ao exterior.Grid ColumnDefinitions mas não consigo obter facilmente uma referência vinculativa a ela.

 5
Author: Brendan, 2014-08-29

3 answers

Este é um dos problemas mais irritantes com a FSM. Uma vez que o espaço disponível cedido à grelha templada é infinito, o conteúdo real tomará tanto espaço quanto quiser.

A maneira mais simples é fixar uma certa largura na grelha, mas isso resolve apenas as situações em que não há redimensionamento.

Considerando que você quer esticar o tamanho da lista (largura, no específico), infelizmente eu acho que não há nenhuma solução melhor do que uma personalizada conversor.

Aqui está a minha solução:

<Window.Resources>
    <local:MyConv x:Key="cv1" />
</Window.Resources>
<Grid>
    <ListBox 
        ItemsSource="{Binding Foo, FallbackValue=1234}"
        HorizontalContentAlignment="Stretch"
        >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}, Converter={StaticResource cv1}}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50*" />
                        <ColumnDefinition Width="100*" />
                        <ColumnDefinition Width="50*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Foo" Grid.Column="0" />
                    <TextBlock Text="Some long text here which overflows" TextTrimming="CharacterEllipsis" Grid.Column="1" />
                    <TextBlock Text="Foo"  Grid.Column="2" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

E o Conversor:

class MyConv : IValueConverter
{
    public object Convert(
        object value, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture
        )
    {
        return (double)value - 30.0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
 5
Author: Mario Vernari, 2014-08-29 12:47:34

Mesmo que este seja um post antigo eu estou adicionando minhas descobertas como eles podem ser relevantes para outras pessoas lendo este post. Eu tinha uma questão semelhante (minhas colunas * não estavam dividindo a largura igualitária como esperado mais, eles estavam apenas dimensionando com base no conteúdo). A causa principal aqui foi que eu tinha uma ListView com um ItemsSource ligado a uma lista. A lista no WPF contém um ScrollViewer e um ScrollViewer não tem uma largura fixa. Sem uma largura fixa, uma grelha não consegue determinar o que largura para dar a uma coluna * e muda para um método de dimensionamento diferente.

Solução Eu agora uso um ItemsControl que não contém um ScrollViewer e, assim, a largura é conhecida permitindo que a grade para tamanho adequado suas colunas.

Para mais detalhes sobre como exactamente a grelha lida com a sua dimensão, sugiro que descompile a classe da grelha e veja o seguinte método:

protected override Size MeasureOverride(Size constraint) 
Esta é a minha janela principal.xaml da minha aplicação de testes (comentar a lista para ver a diferença de comportamento):
 <Window x:Class="WPFSO.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:wpfso="clr-namespace:WPFSO"        
            Title="MainWindow" Height="150" Width="525">
        <Window.DataContext>
            <wpfso:SharedSizeScopeViewModel />
        </Window.DataContext>
        <Window.Resources>
            <DataTemplate DataType="{x:Type wpfso:TestViewModel}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" x:Name="SecondColumn" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" x:Name="FourthColumn" />
                    </Grid.ColumnDefinitions>

                    <TextBlock Grid.Column="0" Text="{Binding Name}" />
                    <TextBlock Grid.Column="1" Background="LightGray" Text="{Binding Name2}"/>                
                    <TextBlock Grid.Column="2" Text="{Binding Name3}"/>
                    <TextBlock Grid.Column="3" Background="Orange" Text="{Binding Name4}"/>

                    <!--<TextBlock Grid.Column="1" Background="Blue" HorizontalAlignment="Stretch" />
                    <TextBlock Grid.Column="3" Background="Orange" HorizontalAlignment="Stretch" />-->
                </Grid>
            </DataTemplate>

            <DataTemplate x:Key="MainDataTemplate" DataType="wpfso:SharedSizeScopeViewModel" >
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>

                    <CheckBox Grid.Row="0" Grid.ColumnSpan="4" HorizontalAlignment="Left" FlowDirection="RightToLeft" Margin="0,0,0,25">
                        <TextBlock FlowDirection="LeftToRight" Text="Show differences" Style="{StaticResource LabelStyle}" />
                    </CheckBox>

                    <TextBlock Grid.Row="1" Grid.Column="0" Text="PropertyName" Style="{StaticResource LabelStyle}" />
                    <TextBlock Grid.Row="1" Grid.Column="1" Text="Previous value" Style="{StaticResource LabelStyle}" />
                    <TextBlock Grid.Row="1" Grid.Column="3" Text="Current value" Style="{StaticResource LabelStyle}" />

                    <ListView Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4"  ItemsSource="{Binding Entries}" HorizontalAlignment="Stretch" Margin="0" HorizontalContentAlignment="Stretch"/>
                </Grid>
            </DataTemplate>
        </Window.Resources>
        <Grid Name="RootGrid">

           <ItemsControl ItemsSource="{Binding Entries}" />
           <!--<ListView ItemsSource="{Binding Entries}" />-->

        </Grid>
    </Window>

The ViewModels used during this test:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPFSO
{
    public class SharedSizeScopeViewModel : INotifyPropertyChanged
    {

        public SharedSizeScopeViewModel()
        {
            var testEntries = new ObservableCollection<TestViewModel>();

            testEntries.Add(new TestViewModel
            {
                Name = "Test",
                Name2 = "Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test",
                Name3 = "Short test",
                Name4 = "Nothing"


            });

            Entries = testEntries;        
        }

        private ObservableCollection<TestViewModel> _entries;

        public ObservableCollection<TestViewModel> Entries
        {
            get { return _entries; }
            set
            {
                _entries = value; 
                OnPropertyChanged();
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

First viewmodel

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPFSO
{
    public class SharedSizeScopeViewModel : INotifyPropertyChanged
    {

        public SharedSizeScopeViewModel()
        {
            var testEntries = new ObservableCollection<TestViewModel>();

            testEntries.Add(new TestViewModel
            {
                Name = "Test",
                Name2 = "Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test",
                Name3 = "Short test",
                Name4 = "Nothing"


            });

            Entries = testEntries;        
        }

        private ObservableCollection<TestViewModel> _entries;

        public ObservableCollection<TestViewModel> Entries
        {
            get { return _entries; }
            set
            {
                _entries = value; 
                OnPropertyChanged();
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Second viewmodel

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPFSO
{
    public class TestViewModel : INotifyPropertyChanged
    {    
        private string _name;
        private string _name2;
        private string _name3;
        private string _name4;

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged();
            }
        }

        public string Name2
        {
            get { return _name2; }
            set
            {
                _name2 = value;
                OnPropertyChanged();
            }
        }

        public string Name3
        {
            get { return _name3; }
            set
            {
                _name3 = value;
                OnPropertyChanged();
            }
        }

        public string Name4
        {
            get { return _name4; }
            set
            {
                _name4 = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
 1
Author: Starceaker, 2016-02-12 08:54:41

Conjunto

TextTrimming="CharacterEllipsis"
No bloco de texto. Para mim, funciona. Como você definiu a coluna do meio deve ser o dobro do tamanho da outra.
 0
Author: AxdorphCoder, 2014-08-29 12:02:11