WPF DataGrid: Липсва празен ред

Създавам WPF прозорец с DataGrid и искам да покажа празния ред „нов елемент“ в долната част на мрежата, който ми позволява да добавя нов елемент към мрежата. По някаква причина празният ред не се показва в решетката на моя прозорец. Ето маркирането, което използвах, за да създам DataGrid:

<toolkit:DataGrid  x:Name="ProjectTasksDataGrid" 
                   DockPanel.Dock="Top" 
                   Style="{DynamicResource {x:Static res:SharedResources.FsBlueGridKey}}"
                   AutoGenerateColumns="False" 
                   ItemsSource="{Binding SelectedProject.Tasks}" 
                   RowHeaderWidth="0" 
                   MouseMove="OnStartDrag" 
                   DragEnter="OnCheckDropTarget" 
                   DragOver="OnCheckDropTarget" 
                   DragLeave="OnCheckDropTarget" 
                   Drop="OnDrop" 
                   InitializingNewItem="ProjectTasksDataGrid_InitializingNewItem">
    <toolkit:DataGrid.Columns>
        <toolkit:DataGridCheckBoxColumn HeaderTemplate="{DynamicResource {x:Static res:SharedResources.CheckmarkHeaderKey}}" Width="25" Binding="{Binding Completed}" IsReadOnly="false"/>
        <toolkit:DataGridTextColumn Header="Days" Width="75" Binding="{Binding NumDays}" IsReadOnly="false"/>
        <toolkit:DataGridTextColumn Header="Due Date" Width="75" Binding="{Binding DueDate, Converter={StaticResource standardDateConverter}}" IsReadOnly="false"/>
        <toolkit:DataGridTextColumn Header="Description" Width="*" Binding="{Binding Description}" IsReadOnly="false"/>
    </toolkit:DataGrid.Columns>
</toolkit:DataGrid>

Не мога да разбера защо празният ред не се показва. Опитах очевидните неща (IsReadOnly="false", CanUserAddRows="True"), без успех. Някаква идея защо празният ред е деактивиран? Благодаря за вашата помощ.


person David Veeneman    schedule 23.09.2009    source източник


Отговори (7)


Винсент Сибал публикува статия, описваща какво е необходимо за добавяне на нови редове към DataGrid. Има доста възможности и повечето от тях зависят от типа колекция, която използвате за SelectedProject.Tasks.

Бих препоръчал да се уверите, че Tasks не е колекция само за четене и че поддържа един от необходимите интерфейси (споменати в предишната връзка), за да позволи правилното добавяне на нови елементи с DataGrid.

person Reed Copsey    schedule 23.09.2009
comment
Всъщност Tasks е ObservableCollection‹T›. Направих тестов проект, свързващ мрежа с данни към същия вид колекция и празният ред присъства в долната част на мрежата. Публикацията в блога на Винсент е добра, но той звучи така, сякаш трябва да внедрите IEditableObject, което не е така. Обикновен ванилен DataGrid, обвързан с ObservableCollection‹T›, трябва да показва празния ред. Вижте codeproject.com/KB/WPF/MVVM_DataGrid.aspx. - person David Veeneman; 23.09.2009
comment
Благодаря ви много, че беше полезно. На Ваше разположение. - person Alaa Jabre; 06.07.2013

Трябва също така да имате конструктор по подразбиране за типа в колекцията.

person Community    schedule 30.01.2010
comment
Това е отговорът, който трябваше да бъде отметнат ›.‹ Благодаря на случаен потребител! - person mpen; 12.01.2011
comment
Да, това е отговорът на същия проблем, който имах. - person Xenan; 25.04.2011
comment
Ами ако колекцията е от интерфейсен тип? ObservableCollection<IThing> - person Nick Strupat; 19.03.2013
comment
Пропуснах този правилен отговор, защото е на bootom без код. - person Danil; 28.04.2015
comment
Трябва също да се отбележи, че конструкторът трябва да бъде public. Изглежда, че DataGrid не взема предвид internal или private конструктори. - person Chris Altig; 12.03.2020

Най-накрая се върнах към този. Няма да променя приетия отговор (зелена отметка), но ето причината за проблема:

Моят модел на изглед обгръща класовете на домейна, за да осигури инфраструктура, необходима на WPF. Написах статия за CodeProject относно метода на обвиване, който използвам , който включва клас колекция, който има два параметъра тип:

VmCollection<VM, DM>

където DM е обвит домейн клас, а DM е WPF класът, който го обвива.

Оказва се, че по някаква странна причина наличието на параметър за втори тип в класа на колекцията кара WPF DataGrid да стане нередактируем. Поправката е да се елиминира вторият тип параметър.

Не мога да кажа защо това работи, само че работи. Надявам се да помогне на някой друг по пътя.

person David Veeneman    schedule 28.10.2009

Според мен това е грешка в DataGrid. Връзката на Майк Бландфорд ми помогна за да разберем най-накрая какъв е проблемът: DataGrid не разпознава типа на редовете, докато не обвърже реален обект. Редът за редактиране не се появява b/c мрежата с данни не знае типовете колони. Бихте си помислили, че обвързването на строго типизирана колекция ще работи, но не е така.

За да разширите отговора на Майк Бландфорд, първо трябва да присвоите празната колекция и след това да добавите и премахнете ред. Например,

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        // data binding
        dataGridUsers.ItemsSource = GetMembershipUsers();
        EntRefUserDataSet.EntRefUserDataTable dt = (EntRefUserDataSet.EntRefUserDataTable)dataGridUsers.ItemsSource;
        // hack to force edit row to appear for empty collections
        if (dt.Rows.Count == 0)
        {
            dt.AddEntRefUserRow("", "", false, false);
            dt.Rows[0].Delete();
        }
    }
person Brett    schedule 06.09.2011

Добавете празен елемент към вашия ItemsSource и след това го премахнете. Може да се наложи да зададете CanUserAddRows обратно на true, след като направите това. Прочетох това решение тук : (Публикации от Jarrey и Rick Roen)

Имах този проблем, когато зададох ItemsSource на DefaultView на DataTable и изгледът беше празен. Колоните обаче бяха дефинирани, така че трябваше да може да ги получи. Той Х.

person Mike Blandford    schedule 27.11.2010
comment
уф Благодаря. Това ме подлудява напълно. Най-накрая се отказах от обектите и преминах към набори от въведени данни и дори това се провали. Номерът е първо да присвоите колекцията и след това да я манипулирате чрез добавяне и премахване на обект. - person Brett; 06.09.2011

Това се случи с мен, забравих да обновя инстанцията и това беше кошмар за мен. след като създадох екземпляр на колекцията в onviewloaded, това беше решено.

`observablecollection<T> _newvariable = new observablecollection<T>();`

това реши проблема ми. надявам се, че може да помогне на други

person krunal patel    schedule 02.08.2018

За мен най-добрият начин за внедряване на редактируем асинхронен DataGrid изглежда така:

Преглед на модела:

 public class UserTextMainViewModel : ViewModelBase
{ 
    private bool _isBusy;
    public bool IsBusy
    {
        get { return _isBusy; }
        set
        {
            this._isBusy = value;
            OnPropertyChanged();
        }
    }




    private bool _isSearchActive;
    private bool _isLoading;


    private string _searchInput;
    public string SearchInput
    {
        get { return _searchInput; }
        set
        {
            _searchInput = value;
            OnPropertyChanged();

            _isSearchActive = !string.IsNullOrEmpty(value);
            ApplySearch();
        }
    }

    private ListCollectionView _translationsView;
    public ListCollectionView TranslationsView
    {
        get
        {
            if (_translationsView == null)
            {
                OnRefreshRequired();
            }

            return _translationsView;
        }
        set
        {
            _translationsView = value;
            OnPropertyChanged();
        }
    }


    private void ApplySearch()
    {
        var view = TranslationsView;

        if (view == null) return;

        if (!_isSearchActive)
        {
            view.Filter = null;
        }
        else if (view.Filter == null)
        {
            view.Filter = FilterUserText;
        }
        else
        {
            view.Refresh();
        }
    }

    private bool FilterUserText(object o)
    {
        if (!_isSearchActive) return true;

        var item = (UserTextViewModel)o;

        return item.Key.Contains(_searchInput, StringComparison.InvariantCultureIgnoreCase) ||
               item.Value.Contains(_searchInput, StringComparison.InvariantCultureIgnoreCase);
    }




    private ICommand _clearSearchCommand;
    public ICommand ClearSearchCommand
    {
        get
        {
            return _clearSearchCommand ??
                   (_clearSearchCommand =
                    new DelegateCommand((param) =>
                    {
                        this.SearchInput = string.Empty;

                    }, (p) => !string.IsNullOrEmpty(this.SearchInput)));
        }
    }

    private async void OnRefreshRequired()
    {
        if (_isLoading) return;

        _isLoading = true;
        IsBusy = true;
        try
        {
            var result = await LoadDefinitions();
            TranslationsView = new ListCollectionView(result);
        }
        catch (Exception ex)
        {
            //ex.HandleError();//TODO: Needs to create properly error handling
        }

        _isLoading = false;
        IsBusy = false;
    }


    private async Task<IList> LoadDefinitions()
    {
        var translatioViewModels = await Task.Run(() => TranslationRepository.Instance.AllTranslationsCache
        .Select(model => new UserTextViewModel(model)).ToList());
        return translatioViewModels;
    }


}

XAML:

<UserControl x:Class="UCM.WFDesigner.Views.UserTextMainView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:model="clr-namespace:Cellebrite.Diagnostics.Model.Entities;assembly=Cellebrite.Diagnostics.Model"
         xmlns:System="clr-namespace:System;assembly=mscorlib"
         xmlns:converters1="clr-namespace:UCM.Infra.Converters;assembly=UCM.Infra"
         xmlns:core="clr-namespace:UCM.WFDesigner.Core"
         mc:Ignorable="d"
         d:DesignHeight="300"
         d:DesignWidth="300">


<DockPanel>
    <StackPanel Orientation="Horizontal"
                DockPanel.Dock="Top"
                HorizontalAlignment="Left">


        <DockPanel>

            <TextBlock Text="Search:"
                       DockPanel.Dock="Left"
                       VerticalAlignment="Center"
                       FontWeight="Bold"
                       Margin="0,0,5,0" />

            <Button Style="{StaticResource StyleButtonDeleteCommon}"
                    Height="20"
                    Width="20"
                    DockPanel.Dock="Right"
                    ToolTip="Clear Filter"
                    Command="{Binding ClearSearchCommand}" />

            <TextBox Text="{Binding SearchInput, UpdateSourceTrigger=PropertyChanged}"
                     Width="500"
                     VerticalContentAlignment="Center"
                     Margin="0,0,2,0"
                     FontSize="13" />

        </DockPanel>
    </StackPanel>
    <Grid>
        <DataGrid ItemsSource="{Binding Path=TranslationsView}"
                  AutoGenerateColumns="False"
                  SelectionMode="Single"
                  CanUserAddRows="True">
            <DataGrid.Columns>
              <!-- your columns definition is here-->
            </DataGrid.Columns>
        </DataGrid>
        <!-- your "busy indicator", that shows to user a message instead of stuck data grid-->
        <Border Visibility="{Binding IsBusy,Converter={converters1:BooleanToSomethingConverter TrueValue='Visible', FalseValue='Collapsed'}}"
                Background="#50000000">
            <TextBlock Foreground="White"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"
                       Text="Loading. . ."
                       FontSize="16" />
        </Border>
    </Grid>
</DockPanel>

This pattern allows to work with data grid in a quite simple way and code is very simple either. Do not forget to create default constructor for class that represents your data source.

person Mr.B    schedule 09.06.2016