รับข้อความของกล่องข้อความที่อยู่ภายใน DataGridTemplateColumn ใน DataGrid

ฉันมี DataGrid พร้อมบางคอลัมน์ หนึ่งในนั้นคือคอลัมน์เทมเพลต TemplateColumn นั้นถูกประกาศดังแสดงด้านล่าง:

<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>

ข้อกำหนด :

รับข้อความภายใน TextBlock ที่อยู่ใน CellTemplate ในลักษณะทั่วไป

สิ่งที่ฉันได้ลองแล้ว :

เมื่อฉันกด Enter บนเซลล์ของ TemplateColumn ฉันต้องการข้อความภายใน TextBlock ดังนั้นฉันจึงใช้เหตุการณ์ PreviewKeyDown ของ DataGrid ดังนี้:

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
                }
            }
        }
    }
}

รหัสที่อธิบายข้างต้นส่งคืน ContentPresenter แทน TextBlock ทำไมสิ่งนี้ถึงเกิดขึ้น?

นอกจากนี้ เนื้อหาของ ContentPresenter ยังเป็นโมฆะ


person Vishal    schedule 13.07.2014    source แหล่งที่มา
comment
คุณผูกมัดกับ FirstName แล้ว ทำไมไม่เข้าถึง DataContext และใช้คุณสมบัติ FirstName ล่ะ   -  person d.moncada    schedule 13.07.2014
comment
stackoverflow.com/questions/16997951/   -  person Sajeetharan    schedule 13.07.2014
comment
@d.moncada ขออภัยที่ตอบช้าเนื่องจากไฟฟ้าขัดข้อง ทันทีที่ฉันป้อนข้อมูลลงในเซลล์แล้วกด Enter ฉันต้องการค่าของมัน ในเวลานั้นคุณสมบัติ FirstName เป็นโมฆะ ดังนั้นฉันจึงใช้สิ่งนั้นไม่ได้   -  person Vishal    schedule 14.07.2014
comment
@Sajeetharan ขออภัยที่ตอบช้าเนื่องจากมีไฟฟ้าขัดข้อง ฉันได้เข้าไปเยี่ยมชมเพจที่คุณแนะนำแล้ว ที่นั่นผู้ตอบใช้เมธอด FindChild ซึ่งคาดว่าจะมีพารามิเตอร์ชื่อ แต่ฉันกำลังพัฒนาบางอย่าง เช่น การควบคุมแบบใช้ซ้ำได้ ดังนั้นนักพัฒนาที่จะใช้การควบคุมนี้อาจไม่ระบุชื่อหรือฉันอาจไม่สามารถเดาชื่อของการควบคุมได้ ดังนั้นฉันต้องการแนวทางทั่วไป   -  person Vishal    schedule 14.07.2014
comment
นอกจากนี้ในโค้ดด้านบนที่ฉันให้ไว้ในคำถามยังให้ ContentPresenter แทน Textblock ในบรรทัดนี้: var CellTemplate = ((DataGridCell)dep).Content;   -  person Vishal    schedule 14.07.2014
comment
โปรดอธิบายว่าเป้าหมายที่แท้จริงของคุณคืออะไร เช่น สิ่งที่คุณจะทำหลังจากมีเนื้อหาบล็อกข้อความแล้ว เวลาส่วนใหญ่จะมีวิธีแก้ปัญหาที่ดีที่เกี่ยวข้องกับกลไกการผูกข้อมูลแทนที่จะใช้เหตุการณ์ในแบบฟอร์ม   -  person Mike Fuchs    schedule 16.07.2014
comment
@adabyron ฉันกำลังพัฒนา datagrid แบบกำหนดเอง จริงๆ แล้วฉันต้องการตรวจสอบว่าเซลล์ (ซึ่งขณะนี้ได้รับการแก้ไขก่อนที่จะกดปุ่ม Enter) มีค่าบางส่วนหรือไม่ หากมีค่าบางอย่าง โฟกัสควรไปยังเซลล์ถัดไป มิฉะนั้นควรดำเนินการไปยังตัวควบคุมถัดไป   -  person Vishal    schedule 16.07.2014


คำตอบ (3)


ในการผูกคุณสามารถใช้ UpdateSourceTrigger=PropertyChanged ดังนั้นใน DataGrid_PreviewKeyDown คุณจะไม่พบคุณสมบัติ FirstName เป็นโมฆะ

<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>

และในเหตุการณ์ DataGrid_PreviewKeyDown คุณจะได้รับรายการข้อมูลแถวดังนี้ และคราวนี้คุณจะไม่ได้รับคุณสมบัติ Name เป็นโมฆะ

    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

ความคิดเห็นบางส่วนระบุว่าการเข้าถึง ViewModel อาจเป็นตัวเลือกที่นี่ แม้ว่าวิธีนี้จะเป็นวิธีที่ง่ายกว่าในบางกรณี แต่ก็ไม่ได้จัดการกับฟิลด์ที่ไม่มีข้อมูลผูกไว้ และมีแนวโน้มว่าจะเป็นแบบทั่วไปน้อยกว่าจริงๆ

สิ่งที่เราต้องการทำคือหาลูก TextBlock คนแรกเดินลงมาตาม VisualTree ของ DataGridCell ที่ถูกคลิก พิจารณาตัวอย่างต่อไปนี้:

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

ในโค้ดด้านหลัง:

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
            }
        }
    }
}

ความมหัศจรรย์อยู่ที่เมธอด FindVisualChild (การใช้งานด้านล่าง) วิธีการนี้จะเดินลงไปที่เด็ก ๆ ทุกคนจนกว่าจะพบกล่องข้อความแรกที่เกิดขึ้นในการค้นหาเชิงลึกก่อน ประโยชน์เพิ่มเติมคือใช้งานได้กับคอลัมน์ที่สร้างอัตโนมัติแบบมาตรฐานเช่นกัน

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;
}

สำหรับข้อมูลเพิ่มเติมและความเข้าใจเกี่ยวกับวิธีการค้นหาเด็ก โปรดดูที่ หน้านี้ เพื่ออธิบายความแตกต่างระหว่าง แผนผังภาพและแผนผังลอจิคัลใน WPF

person Bas    schedule 16.07.2014

ฉันได้แก้ไขปัญหาของฉันแล้ว ฉันได้รับกล่องข้อความที่กำลังแก้ไขจาก e.OriginalSource

person Vishal    schedule 16.07.2014
comment
คุณช่วยฉันหน่อยได้ไหม คุณทำอย่างนั้นได้อย่างไร? - person RackM; 13.04.2018
comment
@ C.jacking มันนานมาแล้ว แต่ฉันคิดว่าคุณสามารถตรวจสอบมูลค่าของ e.OriginalSource ได้ คุณจะได้รับคุณสมบัติบางอย่างที่มีข้อความในกล่องข้อความของคุณ - person Vishal; 13.04.2018
comment
ฉันใช้ Textblock จะใช้งานได้หรือไม่ ฉันกำลังประสบปัญหาเดียวกันทุกประการ - person RackM; 13.04.2018
comment
@ C.jacking ใช่คุณสามารถลองได้ แต่ฉันออกจาก WPF ก่อน 2 ปีฉันก็เลยจำไม่ได้ - person Vishal; 13.04.2018