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 umDataTemplate
, 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.
3 answers
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();
}
}
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));
}
}
}
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.