powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / DataGrid генерирует пустые строки
7 сообщений из 7, страница 1 из 1
DataGrid генерирует пустые строки
    #38794941
НемоКэп42
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть два потока - расчётный и поток интерфейса. В расчётном обновляется ObservableCollection, плюс есть ещё обработчик на событие CollectionChanged этой коллекции. Как я понял, этот обработчик работает в том же потоке, в котором произошло изменение ObservableCollection - т. е. в моём случае это расчётный поток. Поэтому, чтобы обновить интерфейс по обновлению ObservableCollection, байндинг на эту ObservableCollection не поможет - надо руками через диспетчер заполнять контрол.

И вот я написал код, в котором заполнение листбокса работает, а заполнение датагрида - нет. Датагрид показывает какие-то пустые узкие полоски. Я никак не могу понять, в чём дело.

Вот код, который можно сразу скопировать и запустить:

C#
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MyClass MyCls { get; set; }
        public ObservableCollection<MyClass> MyCollection { get; set; }

        public MainWindow()
        {
            InitializeComponent();


            MyCollection = new ObservableCollection<MyClass>();
            MyCollection.CollectionChanged += MyCollection_CollectionChanged;

            Thread t = new Thread(new ThreadStart(() =>
                {
                    for (int i = 0; i < 10; i++)
                    {
                        MyCollection.Add(new MyClass() { Integer = i, Str = "String" + i });
                        Thread.Sleep(500);
                    }
                }));

            t.Start();
        }

        void MyCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Dispatcher.Invoke(
                () =>
                {
                    foreach (var item in e.NewItems)
                        dataGrid.Items.Add((MyClass)item);
                });
        }
    }

    public class MyClass
    {
        public int Integer { get; set; }
        public string Str { get; set; }
    }
}



XAML (можно раскомментить листбокс а закомментить датагрид, чтобы увидеть, что с листбоксом работает, а с гридом - нет)
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
<Window
  x:Class="WpfApplication1.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">
  <Grid>

    <!--<ListBox
      Name="dataGrid">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <StackPanel>
            <TextBlock
              Text="{Binding Path=Integer}" />
            <TextBlock
              Text="{Binding Path=Str}" />
          </StackPanel>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>-->

    <DataGrid
      Name="dataGrid">
      <DataGrid.ItemTemplate>
        <DataTemplate>
          <StackPanel>
            <TextBlock
              Text="{Binding Path=Integer}" />
            <TextBlock
              Text="{Binding Path=Str}" />
          </StackPanel>
        </DataTemplate>
      </DataGrid.ItemTemplate>
    </DataGrid>
    
  </Grid>
</Window>

...
Рейтинг: 0 / 0
DataGrid генерирует пустые строки
    #38794942
НемоКэп42
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Свойство MyCls не нужно.
...
Рейтинг: 0 / 0
DataGrid генерирует пустые строки
    #38796109
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
http://wpftutorial.net/DataGrid.html#manualColumns

в ItemTemplate на сколько я помню определяется шаблон в котором должен быть ContentPresenter, в котором уже будет контент строки состоящий из ячеек. Точно не помню, может ItemPresenter или как то еще.
...
Рейтинг: 0 / 0
DataGrid генерирует пустые строки
    #38796429
Ilya81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ItemsPresenter выводит коллекцию, ContentPresenter - один элемент. Но я не понял, в чём ж всё-таки проблема поставить binding на ItemsSource - иначе он вполне может и не использовать ItemTemplate, тогда нужно добавлять в Item'ы сами control'ы. Или попробуйте использовать вручную ItemContainerGenerator, хотя по мне это было б т. с. реализацией через кое-что.
...
Рейтинг: 0 / 0
DataGrid генерирует пустые строки
    #38797792
НемоКэп42
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes http://wpftutorial.net/DataGrid.html#manualColumns

в ItemTemplate на сколько я помню определяется шаблон в котором должен быть ContentPresenter, в котором уже будет контент строки состоящий из ячеек. Точно не помню, может ItemPresenter или как то еще.
Шаблон данных там, в ItemTemplate, дожен быть.

Ilya81ItemsPresenter выводит коллекцию, ContentPresenter - один элемент. Но я не понял, в чём ж всё-таки проблема поставить binding на ItemsSource - иначе он вполне может и не использовать ItemTemplate, тогда нужно добавлять в Item'ы сами control'ы. Или попробуйте использовать вручную ItemContainerGenerator, хотя по мне это было б т. с. реализацией через кое-что.
Можно и через байндинг, но только, как я уже сказал, событие изменения (и, соответственно, обработчик этого события) для ObservableCollection срабатывает в том потоке, который эту коллекцию изменил. Поэтому, если байндить MyCollection сразу на датагрид, то датагрид обновляться не будет.

Вобщем, как я понял, вариантов два:

1) обновлять вручную, как у меня в примере, но тогда надо вручную же и генерировать столбцы и прочее для датагрида, т. к. AutoGenerateColumns при ручном добавлении строк работать не будет;

2) сделать байндин, но при этом придумать механизм, который бы передавал изменения из потока, произвёдшего изменения, в поток GUI.

Я предпочёл последний вариант. При этом пришлось завести вторую коллекцию. Вообще, смотри http://stackoverflow.com/questions/26727848/datagrid-generates-empty-rows - мне подошёл последний вариант в правильном ответе. Ещё смотри первый комментарий под вопросом.

Как я понял, вариант со второй коллекцией подводит к шаблону MVVM, где рабочий поток, который изменяет MyCollection (в моём примере, или _MyCollection в примере по ссылке), работает с моделью (MyCollection принадлежит модели), а в потоке GUI сидит модель представления со своей коллекцией. Ну и по изменению коллекции модели, изменяется коллекция модели представления, а последняя уже, в свою очередь, автоматом изменяет представление (датагрид) через привязку.

Т. е. вот эта особенность датагрида WPF'овского (не хочет автогенерить строки и столбцы при добавлении данных "вручную") опять говорит о том, что WPF заточен именно на определённую работу, а не абы как. Про это и твердят в т. ч. его создатели - что WPF заточен на MVVM. Если применять что-то другое, то получится какашка.

Та же история с TreeView, например - если добавлять вручную элементы, то запаришься с ним работать, а если через MVVM, то всё как по маслу (только кода много получается) - http://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode
...
Рейтинг: 0 / 0
DataGrid генерирует пустые строки
    #38797796
НемоКэп42
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторThis is yet another example of how WPF requires you to shift mental gears to make use of the platform appropriately. We aren’t in Kansas anymore, Toto.
Не дают работать абы как-нибудь! Прямо связывают по рукам и ногам, редиски!
...
Рейтинг: 0 / 0
DataGrid генерирует пустые строки
    #38798527
Ilya81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
НемоКэп42 сделать байндин, но при этом придумать механизм, который бы передавал изменения из потока, произвёдшего изменения, в поток GUI.
Да ничего и придумывать не надо - если просто модификация коллекции из другого потока, то пишите:
Код: c#
1.
Application.Current.Dispatcher.Invoke(new Action(()=>MyCollection.Add(new MyClass() { Integer = i, Str = "String" + i })));


Если коллекция заменяется, вызываете событие интерфейса INotifyPropertyChanged.
...
Рейтинг: 0 / 0
7 сообщений из 7, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / DataGrid генерирует пустые строки
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]