2014-01-08 102 views
3

How do I place a Popup in my DataGridTemplateColumn.CellEditingTemplate correctly?一樣,我試圖在單元格被編輯時在數據網格的單元格下面出現PopUp,當單元格不再被編輯時消失。最後一點是PopUp的內容根據列是動態的,列是通過綁定動態創建的。編輯WPF DataGrid單元格時顯示彈出窗口

我開始使用以下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> 
+0

最簡單的辦法是設置DataGridCell Focusable屬性設置爲false ,並且Popup獲得焦點。參考這個答案http://stackoverflow.com/a/18027670/1437877 – Abbas

回答

3

我已經想通了,至今運作良好的解決方案。它涉及一些事件處理程序,但代碼不必訪問視圖模型,因此希望它不會引起MVVM純粹主義者的憤怒。

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事件處理程序:

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:

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

我相信一個好的方法是將它設置這樣

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

這似乎做了一些奇怪的行添加行,並沒有創建我的動態列;我也不想用彈出窗口替換正常的單元格編輯行爲,但是彈出顯示補充信息。 –