WPF'de GridViewColumn verileri nasıl otomatik boyutlandırılır ve sağa hizalanır?


89

Nasıl yapabilirim:

  • Kimlik sütunundaki metni sağa hizalayın
  • en uzun görünür veriye sahip hücrenin metin uzunluğuna göre sütunların her birini otomatik boyutlandırın?

İşte kod:

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" Width="40"/>
            <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="100" />
            <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
        </GridView>
    </ListView.View>
</ListView>

kısmi cevap:

Teşekkürler Kjetil, GridViewColumn.CellTemplate iyi çalışıyor ve tabii ki Otomatik Genişlik çalışıyor, ancak ObservativeCollection "Collection" sütun genişliğinden daha uzun verilerle güncellendiğinde, sütun boyutları kendilerini güncelleştirmiyor, bu nedenle verilerin ilk gösterimi:

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" Width="Auto">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Id}" TextAlignment="Right" Width="40"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
            <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
        </GridView>
    </ListView.View>
</ListView>

1
Otomatik boyutlandırma sorununuz için hiç bir çözüm buldunuz mu? Ben de aynı şeyi yaşıyorum.
Oskar

2
@Oskar - listenin sanallaştırılması otomatik çözümü engelliyor. Liste yalnızca o anda görünür olan öğeleri bilir ve boyutu buna göre ayarlar. Listenin ilerleyen kısımlarında daha fazla öğe varsa, bunları bilmiyor ve dolayısıyla onları açıklayamıyor. ProgrammingWPF - Sells-Griffith kitabı, veri bağlamayı kullanıyorsanız manuel sütun genişliklerini önerir. :(
Gishu

@Gishu Teşekkürler, bu gerçekten mantıklı ..
Oskar

MVVM kullanıyorsanız ve Bağlama değerleri değişiyorsa, lütfen @Rolf Wessels yanıtına bakın.
Jake Berger

Yanıtlar:


104

Sütunların her birinin otomatik boyutlandırılmasını sağlamak için GridViewColumn'da Width = "Auto" ayarını yapabilirsiniz.

Kimlik sütunundaki metni sağa hizalamak için, bir TextBlock kullanarak bir hücre şablonu oluşturabilir ve TextAlignment öğesini ayarlayabilirsiniz. Ardından, hücre şablonunun tüm GridViewCell'i doldurmasını sağlamak için ListViewItem.HorizontalContentAlignment öğesini ayarlayın (ListViewItem üzerinde bir ayarlayıcı ile bir stil kullanarak).

Belki daha basit bir çözüm var ama bu işe yaramalı.

Not: çözüm , CellTemplate içinde hem HorizontalContentAlignment = Stretch in Window.Resources hem de TextAlignment = Right gerektirir.

<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
    <Style TargetType="ListViewItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    </Style>
</Window.Resources>
<Grid>
    <ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="ID" Width="40">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Id}" TextAlignment="Right" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
                <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>
</Window>

@Kjetil - Bu ayarı belirli bir sütuna uygulayabilir miyim?
Gishu

15
+1: <Setter Property = "HorizontalContentAlignment" Value = "Stretch" />
Helge Klein

harika, ama benim 15 sütunum var, hücre şablonunu hepsi için tekrar etmeme gerek yok mu?
Nitin Chaudhari

7
GridViewColumn'dan DisplayMemberBinding'i kaldırmayı unutursanız da çalışmaz. O zaman şablonun herhangi bir etkisi olmayacaktır.
floele

@Mohamed Neden öyle değil?
NotALie.

37

İçeriğin genişliği değişirse, her sütunu güncellemek için bu kod parçasını kullanmanız gerekir:

private void ResizeGridViewColumn(GridViewColumn column)
{
    if (double.IsNaN(column.Width))
    {
        column.Width = column.ActualWidth;
    }

    column.Width = double.NaN;
}

Bu sütunun verileri her güncellendiğinde onu ateşlemeniz gerekir.


1
Bunu neye eklersiniz?
Armentage

1
Kılavuz verilerini güncelledikten sonra GridViewColumn'da manuel olarak çalıştırın. Bir ViewModel'iniz varsa, üzerinde PropertyChanged olayına abone olabilir ve daha sonra çalıştırabilirsiniz.
RandomEngy

+1 Bunun için teşekkürler! Bu bana çok yardımcı oldu! Bu soruyla ilgili değil, ancak yine de: GUI aracılığıyla çalışma zamanında sütunları dinamik olarak ekleyebileceğiniz / kaldırabileceğiniz özelleştirilmiş bir List / GridView uyguladım. Ancak, bir sütunu kaldırıp yeniden eklediğimde artık görünmüyordu. İlk olarak, hiç eklenmediğini düşündüm (bazı nedenlerden dolayı), ancak sonra (Snoop kullanarak) aslında eklendiğini, ancak 0 Gerçek Genişliğe sahip olduğunu öğrendim (otomatik olarak boyutlandırıldı ve sütun olduğunda açıkça sıfırlandı kaldırıldı). Şimdi, kodunuzu, sütunu Sütunlara yeniden ekledikten sonra doğru genişliğe ayarlamak için kullanıyorum. Çok teşekkürler!
gehho

Sorunuma basit bir çözüm!
Gqqnbig

+1 Mükemmel! Bunun cevap olarak işaretlenmesini isterdim. X: Name = "gvcMyColumnName" i sütunun tanımlandığı XAML'ye ekledim, böylece arkasındaki koddan ona erişebildim. Bir şampiyon gibi çalışır.
K0D4

19

Liste görünümünüz de yeniden boyutlandırılıyorsa, sütunları tam ListView genişliğine sığacak şekilde yeniden boyutlandırmak için bir davranış modeli kullanabilirsiniz. Grid.column tanımlarını kullanmakla neredeyse aynı

<ListView HorizontalAlignment="Stretch"
          Behaviours:GridViewColumnResize.Enabled="True">
        <ListViewItem></ListViewItem>
        <ListView.View>
            <GridView>
                <GridViewColumn  Header="Column *"
                                   Behaviours:GridViewColumnResize.Width="*" >
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox HorizontalAlignment="Stretch" Text="Example1" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>

Bazı örnekler ve http://lazycowprojects.tumblr.com/post/7063214400/wpf-c-listview-column-width-auto kaynak koduna bağlantı için aşağıdaki bağlantıya bakın


Bu harika. Sorunu çözer ve aradığınız tüm , n , Otomatik işlevlerini verir .
Designpattern

Bu aradığım şeydi. : D
Jake Berger

Not: Bir hata var gibi görünüyor. ListView dikey olarak yeniden boyutlandırıldığında, dikey bir kaydırma çubuğunun görünmesine neden olan noktaya kadar, kaydırma çubuğu kaybolana kadar sütunun genişliği sürekli olarak artacaktır.
Jake Berger

1
Bu gönderi , önceki yorumumda açıklanan davranış hakkında fikir verebilir.
Jake Berger

Harika, hem kodu hem de siteyi kastediyorum :). Daha katı gereksinimlerim olduğunda faydalı olacağına inanıyorum.
Gqqnbig

12

Aşağıdaki sınıfı oluşturdum ve uygulama genelinde gerekli olan her yerde kullandım GridView:

/// <summary>
/// Represents a view mode that displays data items in columns for a System.Windows.Controls.ListView control with auto sized columns based on the column content     
/// </summary>
public class AutoSizedGridView : GridView
{        
    protected override void PrepareItem(ListViewItem item)
    {
        foreach (GridViewColumn column in Columns)
        {
            // Setting NaN for the column width automatically determines the required
            // width enough to hold the content completely.

            // If the width is NaN, first set it to ActualWidth temporarily.
            if (double.IsNaN(column.Width))
              column.Width = column.ActualWidth;

            // Finally, set the column with to NaN. This raises the property change
            // event and re computes the width.
            column.Width = double.NaN;              
        }            
        base.PrepareItem(item);
    }
}

7

Bir ItemContainerStyle'a sahip olduğum için HorizontalContentAlignment'ı ItemContainerStyle'a koymak zorunda kaldım

    <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=FieldDef.DispDetail, Mode=OneWay}" Value="False">
                         <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </Style.Triggers>
                <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
    ....

6

User1333423'ün çözümünü beğendim, ancak her sütunu her zaman yeniden boyutlandırması; Bazı sütunların sabit genişlikte olmasına izin vermem gerekiyordu. Dolayısıyla, bu sürümde genişliği "Otomatik" olarak ayarlanmış sütunlar otomatik olarak boyutlandırılacak ve sabit bir miktara ayarlananlar otomatik boyutlandırılmayacaktır.

public class AutoSizedGridView : GridView
{
    HashSet<int> _autoWidthColumns;

    protected override void PrepareItem(ListViewItem item)
    {
        if (_autoWidthColumns == null)
        {
            _autoWidthColumns = new HashSet<int>();

            foreach (var column in Columns)
            {
                if(double.IsNaN(column.Width))
                    _autoWidthColumns.Add(column.GetHashCode());
            }                
        }

        foreach (GridViewColumn column in Columns)
        {
            if (_autoWidthColumns.Contains(column.GetHashCode()))
            {
                if (double.IsNaN(column.Width))
                    column.Width = column.ActualWidth;

                column.Width = double.NaN;                    
            }          
        }

        base.PrepareItem(item);
    }        
}

2

Bunun çok geç olduğunu biliyorum ama işte benim yaklaşımım:

<GridViewColumn x:Name="GridHeaderLocalSize"  Width="100">      
<GridViewColumn.Header>
    <GridViewColumnHeader HorizontalContentAlignment="Right">
        <Grid Width="Auto" HorizontalAlignment="Right">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="Local size" TextAlignment="Right" Padding="0,0,5,0"/>
        </Grid>
    </GridViewColumnHeader>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
    <DataTemplate>
        <TextBlock Width="{Binding ElementName=GridHeaderLocalSize, Path=Width, FallbackValue=100}"  HorizontalAlignment="Right" TextAlignment="Right" Padding="0,0,5,0" Text="Text" >
        </TextBlock>
    </DataTemplate>
</GridViewColumn.CellTemplate>

Ana fikir, cellTemplete öğesinin genişliğini ViewGridColumn genişliğine bağlamaktır. Genişlik = 100, ilk yeniden boyutlandırmaya kadar kullanılan varsayılan genişliktir. Arkasında herhangi bir kod yok. Her şey xaml'de.


Bu bana bir sütunun genişliğini doldurmam için bu çözüme ilham verdi: <GridViewColumn Width = "{Binding RelativeSource = {RelativeSource AncestorType = ListView}, Path = ActualWidth}">
J. Andersen

1

Kabul edilen yanıtla ilgili sorun yaşadım (çünkü HorizontalAlignment = Stretch bölümünü kaçırdım ve orijinal yanıtı ayarladım).

Bu başka bir tekniktir. SharedSizeGroup içeren bir Grid kullanır.

Not: Grid.IsSharedScope = true ListView üzerinde.

<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
    <ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}" Grid.IsSharedSizeScope="True">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="ID" Width="40">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                             <Grid>
                                  <Grid.ColumnDefinitions>
                                       <ColumnDefinition Width="Auto" SharedSizeGroup="IdColumn"/>
                                  </Grid.ColumnDefinitions>
                                  <TextBlock HorizontalAlignment="Right" Text={Binding Path=Id}"/>
                             </Grid>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
                <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>
</Window>

Sen genişliği var GridViewColumnolduğu 40ve sütun tanımı genişliğini ayarlamak Auto? Bu mantıklı değil.
BK

1

Bir liste için GridView sütun başlıklarını güncellemek için bir işlev oluşturdum ve pencere yeniden boyutlandırıldığında veya liste görünümü düzenini güncellediğinde onu çağırdım.

public void correctColumnWidths()
{
    double remainingSpace = myList.ActualWidth;

    if (remainingSpace > 0)
    {
         for (int i = 0; i < (myList.View as GridView).Columns.Count; i++)
              if (i != 2)
                   remainingSpace -= (myList.View as GridView).Columns[i].ActualWidth;

          //Leave 15 px free for scrollbar
          remainingSpace -= 15;

          (myList.View as GridView).Columns[2].Width = remainingSpace;
    }
}

0

Bu senin kodun

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" Width="40"/>
            <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="100" />
            <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
        </GridView>
    </ListView.View>
</ListView>

Bunu dene

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding Id}" Width="Auto">
               <GridViewColumnHeader Content="ID" Width="Auto" />
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding FirstName}" Width="Auto">
              <GridViewColumnHeader Content="First Name" Width="Auto" />
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding LastName}" Width="Auto">
              <GridViewColumnHeader Content="Last Name" Width="Auto" />
            </GridViewColumn
        </GridView>
    </ListView.View>
</ListView>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.