Dapatkan Teks TextBox yang berada di dalam DataGridTemplateColumn di DataGrid

Saya memiliki DataGrid dengan beberapa kolom. Salah satunya adalah Kolom Template. TemplateColumn tersebut dideklarasikan seperti gambar di bawah ini:

<DataGridTemplateColumn Header="First Name">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding FirstName}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <TextBox Text="{Binding FirstName}" Loaded="TextBox_Loaded_1"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

Persyaratan :

Dapatkan teks di dalam TextBlock yang berada di dalam CellTemplate dengan cara yang umum.

Apa yang telah saya coba :

Saat saya menekan Enter di sel TemplateColumn, saya ingin Teks di dalam TextBlock. Jadi, saya telah menggunakan Acara PratinjauKeyDown dari DataGrid sebagai berikut:

private void DataGrid_PreviewKeyDown(.............)
{
    If(e.Key == Key.Enter)
    {
        DependencyObject dep = (DependencyObject)e.OriginalSource;

        if(dep != null && dep is DataGridCell)
        {
            var CellTemplate = ((DataGridCell)dep).Content; //gives me ContentPresenter instead of Textblock

            if (CellTemplate is TextBlock)
            {
                if (((TextBlock)CellTemplate).Text.Trim() == "")
                {
                    //Do whatever I want
                }
            }
        }
    }
}

Kode yang dijelaskan di atas mengembalikan ContentPresenter dan bukan TextBlock. Mengapa ini terjadi?

Selain itu, Konten ContentPresenter adalah null.


person Vishal    schedule 13.07.2014    source sumber
comment
Anda sudah mengikat FirstName, jadi mengapa tidak mengakses DataContext dan cukup menggunakan properti FirstName?   -  person d.moncada    schedule 13.07.2014
comment
stackoverflow.com/questions/16997951/   -  person Sajeetharan    schedule 13.07.2014
comment
@d.moncada Maaf atas keterlambatan balasan karena listrik padam. Segera setelah saya memasukkan beberapa data ke dalam sel dan menekan enter, saya ingin nilainya. Saat itu properti FirstName adalah null, jadi saya tidak bisa menggunakannya.   -  person Vishal    schedule 14.07.2014
comment
@Sajeetharan Maaf atas keterlambatan balasan karena listrik padam. Saya telah mengunjungi halaman yang Anda sarankan. Di sana penjawab menggunakan metode FindChild yang mengharapkan parameter nama tetapi saya mengembangkan sesuatu seperti kontrol yang dapat digunakan kembali, sehingga pengembang yang akan menggunakan kontrol ini mungkin tidak memberikan nama atau saya mungkin tidak dapat menebak nama kontrolnya. Jadi, saya ingin pendekatan umum.   -  person Vishal    schedule 14.07.2014
comment
Juga dalam kode di atas yang saya berikan dalam pertanyaan, berikan saya ContentPresenter alih-alih Textblock di baris ini: var CellTemplate = ((DataGridCell)dep).Content;   -  person Vishal    schedule 14.07.2014
comment
Harap jelaskan apa tujuan Anda sebenarnya, yaitu apa yang akan Anda lakukan setelah Anda memiliki konten blok teks. Seringkali ada solusi bagus yang melibatkan mekanisme penyatuan data daripada menggunakan peristiwa formulir.   -  person Mike Fuchs    schedule 16.07.2014
comment
@adabyron saya sedang mengembangkan datagrid khusus. Sebenarnya saya ingin memeriksa apakah sel (yang sedang diedit sebelum tombol enter ditekan) mengandung suatu nilai atau tidak. Jika mengandung beberapa nilai maka fokus harus dilanjutkan ke sel berikutnya, jika tidak maka fokus harus dilanjutkan ke kontrol berikutnya.   -  person Vishal    schedule 16.07.2014


Jawaban (3)


Dalam pengikatan Anda dapat menggunakan UpdateSourceTrigger=PropertyChanged sehingga di DataGrid_PreviewKeyDownAnda tidak akan menemukan properti Nama Depan sebagai nol.

<DataGridTemplateColumn Header="First Name">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding FirstName}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <TextBox Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}" Loaded="TextBox_Loaded_1"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

Dan dalam acara DataGrid_PreviewKeyDown Anda bisa mendapatkan item data baris Anda sebagai berikut dan kali ini Anda tidak akan mendapatkan properti Nama sebagai nol.

    private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            var cell = e.OriginalSource as DataGridCell;
            if (cell != null)
            {
                var dataitem = cell.DataContext;  //Here you can you AS keyword to convert the DataContext to your item type.
                //dataitem.FirstName
            }
        }
    }
person Nitin Joshi    schedule 16.07.2014

Beberapa komentar menunjukkan bahwa mengakses ViewModel mungkin merupakan opsi di sini, meskipun ini akan menjadi pendekatan yang lebih mudah dalam beberapa kasus, ini tidak menangani bidang yang tidak terikat data dan kemungkinan besar akan menjadi kurang umum.

Apa yang ingin kita lakukan adalah menemukan TextBlock anak pertama yang berjalan di VisualTree dari DataGridCell yang diklik. Perhatikan contoh berikut:

<DataGrid Name="Test" PreviewKeyDown="DataGrid_PreviewKeyDown">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="Bla Bla 123" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Dalam kode di belakang:

private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter)
    {
        var pressedCell = e.OriginalSource as DataGridCell;
        if (pressedCell != null)
        {
            var textBlock = FindVisualChild<TextBlock>(pressedCell);
            if (textBlock != null)
            {
                MessageBox.Show("Text: " + textBlock.Text); 
                //or more useful stuff
            }
        }
    }
}

Keajaibannya terletak pada metode FindVisualChild (implementasi di bawah). Metode ini menelusuri semua anak hingga menemukan kemunculan kotak teks pertama dalam pencarian pertama yang mendalam. Manfaat tambahannya adalah ini juga berfungsi untuk kolom standar yang dibuat secara otomatis!

private static T FindVisualChild<T>(DependencyObject item)
    where T : DependencyObject
{
    var childCount = VisualTreeHelper.GetChildrenCount(item);
    var result = item as T;
    //the for-loop contains a null check; we stop when we find the result. 
    //so the stop condition for this method is embedded in the initialization
    //of the result variable.
    for (int i = 0; i < childCount && result == null; i++)
    {
        result = FindVisualChild<T>(VisualTreeHelper.GetChild(item, i));
    }
    return result;
}

Untuk informasi dan pemahaman lebih lanjut tentang cara mencari anak, silakan lihat halaman ini, yang menjelaskan perbedaan antara pohon visual dan pohon logis di WPF.

person Bas    schedule 16.07.2014

Saya telah memecahkan masalah saya. Saya mendapatkan kotak teks yang sedang diedit dari e.OriginalSource.

person Vishal    schedule 16.07.2014
comment
dapatkah Anda membantu saya bagaimana Anda melakukannya? - person RackM; 13.04.2018
comment
@C.jacking Sudah lama sekali, tapi saya rasa Anda dapat memeriksa nilai e.OriginalSource. Di sana Anda akan mendapatkan beberapa properti di mana teks kotak teks Anda tersedia. - person Vishal; 13.04.2018
comment
Saya menggunakan Textblock, apakah itu akan berhasil? Saya menghadapi masalah yang sama persis - person RackM; 13.04.2018
comment
@C.jacking Ya, Anda bisa mencobanya. Tapi saya sudah keluar dari WPF sebelum 2 tahun, jadi saya tidak mengingatnya. - person Vishal; 13.04.2018