更改DataGridTemplateColumn上的可见性仅适用于第一次

时间:2012-02-29 07:34:16

标签: wpf xaml

我正在看answer on how to set the visibility of a data grid column,所以我添加了

 <UserControl.Resources>
    <BooleanToVisibilityConverter x:Key="b2v" />
</UserControl.Resources>    

然后在我的xaml中我有

<DataGridTemplateColumn Visibility="{Binding Source={x:Reference ShowLookupCheckbox}, 
                                             Path=IsChecked
                                             Converter={StaticResource b2v}}" >
 ...
</DataGridTemplateColumn>

当我的应用启动并且复选框已清除时,列已正确折叠。当我选中复选框时,列正确显示。当我再次单击该复选框时,列再次正确折叠。 然而,当我点击第二次启用复选框时,我会收到InvalidOperationException “指定元素已经是另一个元素的逻辑子元素。首先断开它。”

我尝试将模式改为单向,但这没有用。任何人都知道我做错了什么或如何解释这个例外?

我不认为列的内容在没有可见性设置的情况下正常工作,但为了完成起见,这里是我完全忽略的完整xaml ...上面

 <DataGridTemplateColumn.Header>
 <TextBlock  Style="{StaticResource DataGridHeader}">MO Lookup</TextBlock>
 </DataGridTemplateColumn.Header>

 <DataGridTemplateColumn.CellTemplate >
  <DataTemplate >
     <Hots:AutoCompleteBoxEx ToolTip="Start typing a Master Order Id"
                             ItemsSource="{Binding AllMoLines,
                                                  UpdateSourceTrigger=PropertyChanged}"
                             Width="50"
                             HorizontalContentAlignment="Left"
                             FilterMode="StartsWith"
                             IsDropDownOpen="True"
                             IsTextCompletionEnabled="True"
                             LostFocus="MoLineBoxLostFocus"
                             SelectedItem="{Binding Path=SelectedMoLine, Mode=TwoWay}" >

         <Hots:AutoCompleteBoxEx.ItemTemplate>
             <DataTemplate>
                 <Grid Width="500">
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="50" />
                         <ColumnDefinition Width="400" />
                         <ColumnDefinition Width="50" />
                     </Grid.ColumnDefinitions>
                     <TextBlock Text="{Binding HssId, Mode=OneWay}"
                                Grid.Column="0" />
                     <TextBlock Text="{Binding Description, Mode=OneWay}"
                                Grid.Column="1" />
                     <TextBlock Text="{Binding Unit, Mode=OneWay}"
                                Grid.Column="2" />
                 </Grid>
             </DataTemplate>
         </Hots:AutoCompleteBoxEx.ItemTemplate>
     </Hots:AutoCompleteBoxEx>

 </DataTemplate>

[编辑] 以下是Exception堆栈跟踪的前几行。整件事是66行。这是我觉得困惑的AddLogicalChild和ChangeLogicalParent。我不确定为什么选中/取消选中链接到Visibility属性的复选框会导致添加子元素

System.InvalidOperationException was unhandled
  Message=Specified element is already the logical child of another element. Disconnect it first.
  Source=PresentationFramework
  StackTrace:
    at System.Windows.FrameworkElement.ChangeLogicalParent(DependencyObject newParent)
    at System.Windows.FrameworkElement.AddLogicalChild(Object child)
    at System.Windows.Controls.ContentControl.OnContentChanged(Object oldContent, Object newContent)

3 个答案:

答案 0 :(得分:2)

我遇到了类似的问题,经过深入研究后,我找到了以下帖子 - Remove a column from datagrid and add it back again。 该帖子的作者(Jeromeyers)分享:

  

“如果我将创建Column's Header的代码注释为TextBlock,那么一切正常。因此,Column的HeaderContent以某种方式想要切换父母或其他东西。

     

PS&GT;我希望Column的Header成为TextBlock的原因是我可以进行文本换行。“

答案 1 :(得分:1)

据我了解您的问题,您希望在运行时设置网格列的可见性。 您可以创建附加属性并将其与网格列绑定。

(1)附属物

public class GridColumnManager
{

    static GridColumnManager()
    {
        //Allows to set DataContextProperty on the columns. Must only be invoked once per application.
        FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
    }

    public static object GetDataContextForColumns(DependencyObject obj)
    { return obj.GetValue(DataContextForColumnsProperty); }

    public static void SetDataContextForColumns(DependencyObject obj, object value)
    { obj.SetValue(DataContextForColumnsProperty, value); }

    /// <summary>
    /// Allows to set DataContext property on columns of the DataGrid (DataGridColumn)
    /// </summary>
    /// <example><DataGridTextColumn Header="{Binding DataContext.ColumnHeader, RelativeSource={RelativeSource Self}}" /></example>
    public static readonly DependencyProperty DataContextForColumnsProperty =
        DependencyProperty.RegisterAttached(
        "DataContextForColumns", 
        typeof(object),
        typeof(GridColumnManager), 
        new UIPropertyMetadata(OnDataContextChanged));

    /// <summary>
    /// Propogates the context change to all the DataGrid's columns
    /// </summary>
    private static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var grid = d as DataGrid;
        if (grid == null) return;
        var name = grid.Name;

        foreach (DataGridColumn col in grid.Columns)
            col.SetValue(FrameworkElement.DataContextProperty, e.NewValue);
    }



}

(2)它如何与Grid一起使用

<DataGrid CanUserAddRows="True" IsEnabled="True" AutoGenerateColumns="False" CanUserDeleteRows="True" IsSynchronizedWithCurrentItem="True" Height="200" 
              local:GridColumnManager.DataContextForColumns="{Binding Mode=OneWay}"  HorizontalAlignment="Left" Margin="80,90,0,0" 
              Name="dataGrid1" VerticalAlignment="Top" Width="361" ItemsSource="{Binding Employees,Mode=TwoWay,NotifyOnSourceUpdated=True}" >
        <DataGrid.Resources>
            <BooleanToVisibilityConverter x:Key="MyConvertor"/>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Stating Period" MinWidth="200" Width="*" Visibility="{/*Bind here with your element */,
                                                        RelativeSource={RelativeSource Self},
                                                        Converter={StaticResource MyConvertor}}">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding ID}"   />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <TextBox Text="{Binding ID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" />
                    </DataTemplate>                        
                </DataGridTemplateColumn.CellEditingTemplate>                    
            </DataGridTemplateColumn>  </DataGrid.Columns>

    </DataGrid>

答案 2 :(得分:1)

以下内容似乎有效,但它在后面的代码UpdateLayout上使用了对DataGrid的调用。

在列从Collapsed / Hidden更改为Visible后,请在UpdateLayout上调用DataGrid并捕获异常。