在 WPF DataGrid 单元格编辑期间显示弹出窗口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21006888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:27:54  来源:igfitidea点击:

Show popup during editing of WPF DataGrid cell

c#wpfmvvmdatagridpopup

提问by Walter Williams

Along the same lines as How do I place a Popup in my DataGridTemplateColumn.CellEditingTemplate correctly?, I am trying to have a PopUp appear below a cell in a DataGrid when the cell is being edited, and disappear when the cell is no longer being edited. The final thing is that the PopUp contents are dynamic according to the column, and the columns are created dynamically via binding.

如何在我的 DataGridTemplateColumn.CellEditingTemplate 中正确放置弹出窗口相同,我试图在编辑单元格时让一个弹出窗口出现在 DataGrid 中的单元格下方,并在不再编辑单元格时消失。最后就是PopUp的内容是根据列动态的,列是通过绑定动态创建的。

I started out with the following XAML, but I get a XamlParseException "Add value to collection of type 'System.Windows.Controls.ItemCollection' threw an exception".

我从以下 XAML 开始,但我得到一个 XamlParseException“将值添加到类型为 'System.Windows.Controls.ItemCollection' 的集合抛出异常”。

<DataGrid ItemsSource="{Binding Path=Options}">
    <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellEditingTemplate>
            <DataTemplate>
                <Grid>
                    <Popup Placement="Bottom" IsOpen="True" Width="200" Height="100">
                        <TextBlock>Somethingn here</TextBlock>
                    </Popup>
                </Grid>
            </DataTemplate>
        </DataGridTemplateColumn.CellEditingTemplate>
    </DataGridTemplateColumn>
</DataGrid>

回答by Walter Williams

I have figured out a solution that works well so far. It involves some event handlers, but the code does not have to access the view model so hopefully it won't incur the wrath of MVVM purists.

到目前为止,我已经找到了一个运行良好的解决方案。它涉及一些事件处理程序,但代码不必访问视图模型,因此希望它不会招致 MVVM 纯粹主义者的愤怒。

XAML:

XAML:

<Grid>
    <DataGrid ItemsSource="{Binding Path=Options}" BeginningEdit="DataGrid_BeginningEdit" CellEditEnding="DataGrid_CellEditEnding" />
    <Popup Name="pop1">
        <Border Width="300" Height="200" Background="LemonChiffon" BorderThickness="2" BorderBrush="Black" />
    </Popup>
</Grid>

MainWindow.xaml.cs event handlers:

MainWindow.xaml.cs 事件处理程序:

private void DataGrid_BeginningEdit (Object sender, DataGridBeginningEditEventArgs e)
{
    DataGrid grid = (DataGrid) sender;
    Popup pop1 = (Popup) grid.FindName("pop1");
    pop1.PlacementTarget = grid.GetCell(e.Row.GetIndex(), e.Column.DisplayIndex);
    pop1.IsOpen = true;
}

private void DataGrid_CellEditEnding (Object sender, DataGridCellEditEndingEventArgs e)
{
    Popup pop1 = (Popup) ((DataGrid) sender).FindName("pop1");
    pop1.IsOpen = false;
}

DataGridExtensions.cs:

DataGridExtensions.cs:

/// <summary>
/// Extension methods for DataGrid
/// These methods are thanks to http://blogs.msdn.com/b/vinsibal/archive/2008/11/05/wpf-datagrid-new-item-template-sample.aspx
/// </summary>
public static class DataGridExtensions
{
    /// <summary>
    /// Returns a DataGridCell for the given row and column
    /// </summary>
    /// <param name="grid">The DataGrid</param>
    /// <param name="row">The zero-based row index</param>
    /// <param name="column">The zero-based column index</param>
    /// <returns>The requested DataGridCell, or null if the indices are out of range</returns>
    public static DataGridCell GetCell (this DataGrid grid, Int32 row, Int32 column)
    {
        DataGridRow gridrow = grid.GetRow(row);
        if (gridrow != null)
        {
            DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(gridrow);

            // try to get the cell but it may possibly be virtualized
            DataGridCell cell = (DataGridCell) presenter.ItemContainerGenerator.ContainerFromIndex(column);
            if (cell == null)
            {
                // now try to bring into view and retreive the cell
                grid.ScrollIntoView(gridrow, grid.Columns[column]);

                cell = (DataGridCell) presenter.ItemContainerGenerator.ContainerFromIndex(column);
            }

            return (cell);
        }

        return (null);
    }

    /// <summary>
    /// Gets the DataGridRow based on the given index
    /// </summary>
    /// <param name="idx">The zero-based index of the container to get</param>
    public static DataGridRow GetRow (this DataGrid dataGrid, Int32 idx)
    {
        DataGridRow row = (DataGridRow) dataGrid.ItemContainerGenerator.ContainerFromIndex(idx);
        if (row == null)
        {
            // may be virtualized, bring into view and try again
            dataGrid.ScrollIntoView(dataGrid.Items[idx]);
            dataGrid.UpdateLayout();

            row = (DataGridRow) dataGrid.ItemContainerGenerator.ContainerFromIndex(idx);
        }

        return (row);
    }

    private static T GetVisualChild<T> (Visual parent) where T : Visual
    {
        T child = default(T);

        Int32 numvisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (Int32 i = 0; i < numvisuals; ++i)
        {
            Visual v = (Visual) VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
                child = GetVisualChild<T>(v);
            else
                break;
        }

        return child;
    }
}

回答by Jim

I believe a good approach is to set it up like this

我相信一个好的方法是这样设置

<Grid>
    <DataGrid Name="DataGridList" ItemsSource="{Binding SettingsList, Mode=TwoWay}" AutoGenerateColumns="False" Height="146">
        <!--Resources-->
        <DataGrid.Resources>               
            <!--DataTemplate-->
            <DataTemplate x:Key="DateTemplate" >
                <StackPanel>
                    <TextBlock Text="{Binding YourBinding}"></TextBlock>
                </StackPanel>
            </DataTemplate>              
            <!--EditingDateTemplate-->
            <DataTemplate x:Key="EditingDateTemplate">
                <Grid>
                    <Popup Placement="Bottom" IsOpen="True" Width="200" Height="100">
                        <TextBlock>Something here</TextBlock>
                    </Popup>
                </Grid>
            </DataTemplate>
        </DataGrid.Resources>
        <!--Datagrid-->
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="header 1" CellTemplate="{StaticResource DateTemplate}" CellEditingTemplate="{StaticResource EditingDateTemplate}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>