Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WPF, Silverlight Новый топик    Ответить
 Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
BindingHorror
Guest
Ситуация: имеется DataGrid с кастомной колонкой, унаследованной от DataGridBoundColumn (здесь и ниже код максимально упрощен для приведения в качестве примера):
public class DataGridCustomBoundColumn : DataGridBoundColumn
{
  protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
  {
    var tb = new TextBlock();
    tb.SetBinding(TextBlock.TextProperty, new Binding
    {
      Path = ((Binding)Binding).Path,
      Source = dataItem
    });
    return tb;
  }

  protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
  {
    throw new NotImplementedException();
  }
}

Заполнение данных:
public partial class MainWindow
{
  public MainWindow()
  {
    InitializeComponent();
    Digits = new ObservableCollection<Digits>();
    for (var i = 0; i < 500; i++)
      Digits.Add(new Digit {N = i});
    DataContext = this;
  }

  public ObservableCollection<Digit> Digits { get; private set; }
}

public class Digit
{
  public int N { get; set; }
}

Разметка:
<DataGrid
  ItemsSource="{Binding Digits}"
  AutoGenerateColumns="False"
  IsReadOnly="True"
  Style="{StaticResource DataGridStyle}"
  CellStyle="{StaticResource WxCellStyle}">
  <DataGrid.Columns>
    <DataGridTextColumn
      Header="TextColumn"
      Binding="{Binding N}"/>
    <DataGridTemplateColumn Header="TemplateColumn">
      <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding N}"/>
        </DataTemplate>
      </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    <l:DataGridCustomBoundColumn
      Header="CustomBoundColumn"
      Binding="{Binding N}"/>
  </DataGrid.Columns>
</DataGrid>

В результате в той части окна, которая видна непосредственно в скроллере грида, данные отображаются корректно, если начать скроллить, то данные в сustom DataGridBoundColumn отображаются в странном порядке - практически в произвольном (см. скриншот ниже). Порылся в гугле - нашел, что один человек уже сталкивался с таким: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/08fa78c6-5d25-434d-b00d-19380e84a31e/ - ему предложили отключить виртуализацию грида (VirtualizingStackPanel.IsVirtualizing = False). В моем случае это совсем не вариант, т.к. данных в гриде предполагается достаточно много, и отключение виртуализации даже в приведенном тестовом примере вызывает заметные тормоза при загрузке данных модели. Что еще можно предпринять в этом случае?

К сообщению приложен файл. Размер - 8Kb
20 май 13, 14:57    [14321528]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
BindingHorror
Guest
P.S. WPF 4.0, MSVS 2010 Prof, WinXP SP3 Prof.
20 май 13, 15:05    [14321582]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13632
BindingHorror
Потому что забиндено на dataItem. При дефолтном в гриде режиме виртуализации он меняется из-за повторного использования контейнеров элементов (DataGridRow). Надо биндиться на DataContext TextBlock-а.
20 май 13, 15:27    [14321766]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13632
Вроде как надо просто убрать Source = dataItem в описании биндинга. По дефолту будет привязка к DataContext.
20 май 13, 15:28    [14321777]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
BindingHorror
Guest
Алексей К,

Точно, так оно и есть - убрал Source = dataItem, и все заработало, как надо. Спасибо.
20 май 13, 15:40    [14321853]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
JackTheReaper
Guest
Дабы не создавать новой темы, спрошу тут, надеюсь автор будет не против.

WPF 4.5. Есть DataGrid VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling", хочу сделать CurrentCell индикатор на DataGridRowHeader'e, создал соответствующее attachedproperty, при смене CurrentCell, получаю этот DataGridCell и устанавливаю IsCurrentCell (attachedproperty), в Template DataGridRowHeader добавил Path (тот самый индикатор) visibility биндю к этому самому attachedproperty. Все работает отлично без виртуализации, но с виртуализацией этот индикатор сползает при вертикальном скроллинге, понятно почему так происходит, но как правильно сделать подобный бинд не соображу. И еще, возможно ли сделать при ScrollViewer.IsDeferredScrollingEnabled="True" DeferredScroll только по вертикали? Можно в эвенте смотреть как скролится и менять IsDeferredScrollingEnabled, если, конечно, по другому нельзя. Спасибо!
21 май 13, 23:41    [14329930]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6029
JackTheReaper,

Зачем этот огород с attached property, когда у DataGridRowHeader уже есть а) свойство IsRowSelected; б) visual states Normal_CurrentRow / Normal_CurrentRow_Selected / Unfocused_CurrentRow_Selected (см. здесь)?
22 май 13, 06:26    [14330229]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
JackTheReaper
Guest
Сон Веры Павловны
JackTheReaper,

Зачем этот огород с attached property, когда у DataGridRowHeader уже есть а) свойство IsRowSelected; б) visual states Normal_CurrentRow / Normal_CurrentRow_Selected / Unfocused_CurrentRow_Selected (см. здесь)?


а) Не подходит, так как может быть несколько выбранных строк и для каждой будет видим индикатор
б) как с этим работать? Как сделать биндинг, например к Normal_CurrentRow_Selected?
23 май 13, 21:28    [14341093]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6029
JackTheReaper
Как сделать биндинг, например к Normal_CurrentRow_Selected?

Никак. Откройте для себя VisualStateManager и стили на основе visual states.
24 май 13, 06:29    [14342077]     Ответить | Цитировать Сообщить модератору
 Re: Custom DataGridBoundColumn+Virtualizing: неправильная работа биндинга  [new]
JackTheReaper
Guest
Сон Веры Павловны
JackTheReaper
Как сделать биндинг, например к Normal_CurrentRow_Selected?

Никак. Откройте для себя VisualStateManager и стили на основе visual states.


Большое спасибо за VisualState, очень полезно. Вот решение на основании VisualState:

                                    <Grid.Resources>
                                        <Storyboard x:Key="storyboarhCollapsedPathCurrent">
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PathCurrent" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </Grid.Resources>
                                    <VisualStateManager.VisualStateGroups>
                                        <VisualStateGroup Name="CommonStates">
                                            <VisualState Name="Normal_CurrentRow"/>
                                            <VisualState Name="Normal_CurrentRow_Selected"/>
                                            <VisualState Name="MouseOver_CurrentRow"/>
                                            <VisualState Name="MouseOver_CurrentRow_Selected"/>
                                            <VisualState Name="Unfocused_CurrentRow"/>
                                            <VisualState Name="MouseOver_Unfocused_CurrentRow"/>                                            
                                            <VisualState Name="Unfocused_CurrentRow_Selected"/>
                                            <VisualState Name="MouseOver_Unfocused_CurrentRow_Selected"/>
                                            <VisualState Name="Normal" Storyboard="{StaticResource storyboarhCollapsedPathCurrent}"/>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>


Единственно что не удобно, так это необходимость указывать все состояния в которых может находиться текущая строка и когда DataGrid теряет фокус, пропадает PathCurrent.
27 май 13, 00:27    [14351789]     Ответить | Цитировать Сообщить модератору
Все форумы / WPF, Silverlight Ответить