Подтвердить что ты не робот

Ширина столбца DataGrid не обновляется автоматически

<DataGridTextColumn Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Binding="{Binding Change}" Width="Auto"/>

Когда значение Change обновляется, его столбец не обновляется, чтобы соответствовать новому значению. Таким образом, столбец остается слишком маленьким, а значение обрезается.
Любые идеи?

4b9b3361

Ответ 1

DataGrid увеличит размеры столбцов, чтобы они соответствовали по мере того, как данные становятся длиннее, но не уменьшают размер столбцов при уменьшении длины данных. В вашем примере вы правильно выравниваете столбец "Изменить" и используете остальную часть пространства для столбца "Имя".

Теперь, когда свойство "Изменить" становится настолько большим, что оно должно увеличить ширину столбца, столбец "Имя" отказывается сжиматься для размещения, поэтому вам нужно принудительно обновить себя.

Следующие шаги должны сделать это для вас (я включил пример приложения в демонстрационную версию):

1) В ваших привязках DataGridTextColumn (все, кроме столбца размера *) установите NotifyTargetUpdated = True.
2) В DataGrid добавьте обработчик события TargetUpdated.
3) В обработчике событий TargetUpdated:
- a) Установите ширину столбца размера DataGrid * равным 0.
- b) Вызвать метод UpdateLayout() в DataGrid.
- c) Установите ширину столбца размера DataGrid * для новой DataGridLength (1, DataGridLengthUnitType.Star)

Пример XAML:

<Window x:Class="DataGridTest.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">
    <Window.Resources>
        <CollectionViewSource x:Key="MyObjectCollection" />
    </Window.Resources>
    <DockPanel>
        <Button DockPanel.Dock="Bottom" Content="Click to Make Item 1s Text Longer" Click="Button_Click" />
        <Grid>
            <DataGrid x:Name="dg" ItemsSource="{Binding Source={StaticResource MyObjectCollection}}" AutoGenerateColumns="False" TargetUpdated="dg_TargetUpdated">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding First}" Width="1*"/>
                    <DataGridTextColumn Binding="{Binding Last, NotifyOnTargetUpdated=True}"  Width="Auto" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>

    </DockPanel>
</Window>

Пример кода:

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.ComponentModel;

namespace DataGridTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<MyObject> myObjectList = new ObservableCollection<MyObject>();

        public MainWindow()
        {
            InitializeComponent();
            (this.FindResource("MyObjectCollection") as CollectionViewSource).Source = this.myObjectList;
            this.myObjectList.Add(new MyObject() { First = "Bob", Last = "Jones" });
            this.myObjectList.Add(new MyObject() { First = "Jane", Last = "Doe" });
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.myObjectList[0].Last = "BillyOBrian";
        }

        private void dg_TargetUpdated(object sender, DataTransferEventArgs e)
        {
            dg.Columns[0].Width = 0;
            dg.UpdateLayout();
            dg.Columns[0].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
        }
    }

    public class MyObject : INotifyPropertyChanged
    {
        private string firstName;
        public string First
        {
            get { return this.firstName; }
            set
            {
                if (this.firstName != value)
                {
                    this.firstName = value;
                    NotifyPropertyChanged("First");
                }
            }
        }

        private string lastName;
        public string Last
        {
            get { return this.lastName; }
            set
            {
                if (this.lastName != value)
                {
                    this.lastName = value;
                    NotifyPropertyChanged("Last");
                }
            }
        }

        public MyObject() { }

        #region -- INotifyPropertyChanged Contract --

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion INotifyPropertyChanged Contract
    }
}

Ответ 2

У меня была аналогичная проблема с моим списком, решение, которое я нашел на how-to-autosize-and-right-align-gridviewcolumn-data-in-wpf здесь, в stackoverflow.

В моем случае это добавляло этот фрагмент кода в обработчик событий, посвященный коллекции, из наблюдаемой коллекции, с которой связано представление списка:

void listview_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
        // this is a listview control
        GridView view = this.View as GridView;
        foreach(GridViewColumn c in view.Columns) {
            if(double.IsNaN(c.Width)) {
                c.Width = c.ActualWidth;
            }
            c.Width = double.NaN;
        }
    }

Он работает для меня, хотя иногда пользователь может заметить "мигать" над столбцами.

Ответ 3

Я не могу помещать это в комментарий, поэтому ставим его как ответ:

<sdk:DataGrid x:Name="dataGrid4" 
Height="160" Margin="0,5,0,10" 
RowHeight="40" AutoGenerateColumns="False" >    
<sdk:DataGrid.Columns>
    <sdk:DataGridTextColumn 
        Header="First Name" 
        Width="SizeToHeader"
        Binding="{Binding FirstName}" 
        FontSize="20" />
    <sdk:DataGridTextColumn 
        Header="Last Name" 
        Width="SizeToCells"
        Binding="{Binding LastName}" 
        FontSize="20" />
    <sdk:DataGridTextColumn 
        Header="Address"
        Width="150"
        Binding="{Binding Address}" >
        <sdk:DataGridTextColumn.ElementStyle>
            <Style TargetType="TextBlock">
                <Setter Property="TextWrapping" Value="Wrap"/>
            </Style>
        </sdk:DataGridTextColumn.ElementStyle>
        <sdk:DataGridTextColumn.EditingElementStyle>
            <Style TargetType="TextBox">
                <Setter Property="Foreground" Value="Blue"/>
            </Style>
        </sdk:DataGridTextColumn.EditingElementStyle>
    </sdk:DataGridTextColumn>
    <sdk:DataGridCheckBoxColumn 
        Header="New?" 
        Width="40"
        Binding="{Binding IsNew}" />
    <sdk:DataGridCheckBoxColumn 
        Header="Subscribed?" 
        Width="Auto"
        Binding="{Binding IsSubscribed}" 
        IsThreeState="True" />
</sdk:DataGrid.Columns>

Ответ 4

WPF будет просто изменять размер ширины столбца datagrid, если необходимо, Auto, т.е. содержимое не может быть полностью отображено. Поэтому, когда ширина содержимого уменьшается, столбец не изменяется, поскольку содержимое все еще можно увидеть полностью.

единственный способ, с помощью которого wpf пересчитать ширину столбцов, должен был бы заставить их всех равным 0, а затем вернуться к авто в коде позади, с одним или двумя updateLayout(), которые были введены, но это не очень приятное программирование: -/

в основном, в вашем коде позади:

foreach (DataGridColumn c in dg.Columns)
    c.Width = 0;

// Update your DG source here

foreach (DataGridColumn c in dg.Columns)
    c.Width = DataGridLength.Auto;

и вам, вероятно, понадобится dg.UpdateLayout() или два, где-то там (после обновления и установки для автоматического восстановления)

Ответ 5

Один из способов решения этой проблемы - определить свойство width столбца в настройке стиля и привязать этот параметр к свойству объекта, к которому вы привязываетесь.

<DataGridTextColumn Binding="{Binding Change}" ElementStyle="{StaticResource ChangeColumnStyle}"/>

В вашем ресурсе:

<Style TargetType="{x:Type DataGridTextColumn }" x:Key="ChangeColumnStyle">
   <Setter Property="Width" Value="{Binding ColumnWidth}"
</Style>

ColumnWidth должен быть свойством вашего объекта. Теперь, если вы обновите это свойство от установщика вашего свойства "Изменить" (с помощью некоторого самоопределяемого алгоритма, принимая во внимание такие вещи, как шрифт), и вызывая:

RaisePropertyChanged("ColumnWidth");

Он должен обновить ширину столбца.

 public int Change
   {
      get { return m_change; }
      set
      {
         if (m_change != value)
         {
            m_change = value;
            ColumnWidth = WidthAlgo(numberOfCharacters);
            RaisePropertyChanged("Change");
            RaisePropertyChanged("ColumnWidth");
         }
      }
   }

Ответ 6

Вы пробовали это?

<DataGridTextColumn Binding="{Binding Path= Id}"  Header="ID" IsReadOnly="True" Width="1*" />

Ответ 7

Пожалуйста, убедитесь, что класс, который вы используете для привязки данных, реализует интерфейс INotifyPropertyChanged, и вы каждый раз добавляете событие PropertyChanged, когда свойство изменения обновляется, как показано в следующем примере:

public class SomeDataClass : INotifyPropertyChanged
{
   private int m_change;

   public event PropertyChangedEventHandler PropertyChanged;
   private void RaisePropertyChanged(string propertyName)
   {
      if (PropertyChanged != null)
      {
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
   }

   // You can't use automatic properties here since you need to call RaisePropertyChanged method
   public int Change
   {
      get { return m_change; }
      set
      {
         if (m_change != value)
         {
            m_change = value;
            RaisePropertyChanged("Change");
         }
      }
   }
}