【问题标题】:Bind datagrid column visibility MVVM绑定 datagrid 列可见性 MVVM
【发布时间】:2011-12-04 09:45:10
【问题描述】:

.Net 3.5

我知道这些列不继承数据上下文,通过阅读其他帖子,我认为这会起作用:

Visibility="{Binding RelativeSource={x:Static RelativeSource.Self},
                     Path=(FrameworkElement.DataContext).IsColumnNameVisible,
                     Converter={StaticResource boolToVisConverter}}"

当然不是.. 输出窗口没有报错,似乎是我找到的资源,但是viewmodel属性是新调用的。

这是整个 DG:

<tk:DataGrid                                        
            VirtualizingStackPanel.IsVirtualizing="False"                                        
            Grid.Column="0"
            AlternationCount="2"
            AreRowDetailsFrozen="True"
            AutoGenerateColumns="False"
            Background="Transparent"
            BorderThickness="0"
            CanUserAddRows="False"
            CanUserReorderColumns="True"
            CanUserResizeRows="False"
            GridLinesVisibility="None"
            ItemsSource="{Binding Employees}"
            SelectionMode="Single"
            ColumnHeaderStyle="{StaticResource columnHeaderStyle}"
            RowHeaderStyle="{StaticResource rowHeaderStyle}"
            CellStyle="{StaticResource cellStyle}"
            RowStyle="{StaticResource rowStyle}" 
            ContextMenu="{StaticResource columnHeaderContextMenu}">
    <tk:DataGrid.Resources>
        <ContextMenu x:Key="columnHeaderContextMenu" ItemsSource="{Binding ColumnHeaderContextMenuItems}" />
        <Style TargetType="{x:Type ScrollBar}">
            <Setter Property="Background" Value="Transparent"/>
        </Style>                                    
        <Style TargetType="{x:Type tk:DataGridColumnHeader}">
            <Setter Property="Background" Value="Transparent"/>
        </Style>
    </tk:DataGrid.Resources>
    <tk:DataGrid.Triggers>
        <EventTrigger RoutedEvent="tk:DataGridRow.MouseDoubleClick">
            <EventTrigger.Actions>
                <BeginStoryboard Storyboard="{StaticResource showDetailGrid}"/>
            </EventTrigger.Actions>
        </EventTrigger>
    </tk:DataGrid.Triggers>
    <tk:DataGrid.Columns>
        <tk:DataGridTextColumn IsReadOnly="True" Header="test" Binding="{Binding Name, Mode=OneWay}" Visibility="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(FrameworkElement.DataContext).IsColumnNameVisible, Converter={StaticResource boolToVisConverter}}"  />
    </tk:DataGrid.Columns>
</tk:DataGrid>

我已经阅读了该问题的几乎所有解决方案,但没有任何效果..

【问题讨论】:

  • 如果您的问题有点不清楚。您是否只是试图根据绑定的 ViewModel 属性使数据列可见或不可见?
  • 您在 &lt;tk:DataGrid.Resources&gt; 中更改了 ContextMenu - 难怪您的窗口 DataContext 无法访问。
  • @ChrisBD:是的,就是这个想法。 VM 属性是通过 datacontext 设置的。
  • @Felix:什么意思?它是一个上下文菜单。为什么这会影响数据上下文的可用性?

标签: c# wpf xaml .net-3.5 wpftoolkit


【解决方案1】:

DataGridColumns 不是可视化树的一部分,因此它们没有连接到 DataGrid 的数据上下文。

让他们连接一起使用像这样的代理元素方法...

  1. 在祖先面板的Resources 中添加代理FrameworkElement
  2. 将其托管到绑定到其Content 的不可见ContentControl 中。
  3. 将此ProxyElement 用作StaticResource 作为可见性绑定中的数据上下文源。

    <StackPanel>
        <StackPanel.Resources>
           <local:BooleanToVisibilityConverter
                  x:Key="BooleanToVisibilityConverter" />
    
           <FrameworkElement x:Key="ProxyElement"
                             DataContext="{Binding}"/>
        </StackPanel.Resources>
        <ContentControl Visibility="Collapsed"
                    Content="{StaticResource ProxyElement}"/>
        <DataGrid AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn
                       Visibility="{Binding DataContext.IsTextColumnVisibile,
                                            Source={StaticResource ProxyElement},
                                            Converter={StaticResource
                                                BooleanToVisibilityConverter}}"
                       Binding="{Binding Text}"/>
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel> 
    

除了DataGridColumn,上述方法还可以很好地将DataContext 连接到Popups 和ContextMenus(即任何未连接到可视化树的元素)。

Silverlight 用户

遗憾的是,silverlight 中不允许使用任何框架元素设置内容控件的内容。所以解决方法是(这只是silverlight的指导代码)......

  1. 将框架元素资源更改为像Textblock 这样的轻量级元素。 (Silverlight 不允许指定 FrameworkElement 类型的静态资源。)

    <StackPanel.Resources>
        <TextBlock x:Key="MyTextBlock" />
    
  2. 编写一个附加属性以将文本块与内容控件保持一致。

    <ContentControl Visibility="Collapsed" 
                    local:MyAttachedBehavior.ProxyElement="{StaticResource MyTextBlock}" />
    
  3. 在附加的依赖属性更改事件处理程序中,设置将内容控件的数据上下文绑定到文本块的。

     private static void OnProxyElementPropertyChanged(
         DependencyObject depObj, DependencyPropertyChangedEventArgs e)
     {
           if (depObj is ContentControl && e.NewValue is TextBlock)
           {
               var binding = new Binding("DataContext");
               binding.Source = depObj;
               binding.Mode = OneWay;
               BindingOperations.SetBinding(
                   (TextBlock)e.NewValue, TextBlock.DataContextProperty, binding);
           }
     }
    

因此,这样文本块可能不会连接到可视化树,但会可能知道数据上下文的变化。

希望这会有所帮助。

【讨论】:

  • 取消选择和重新选择时出现异常:指定元素已经是另一个元素的逻辑子元素。先断开它。你知道为什么吗?
  • 可能是你的ContextMenu ...它只能附加到一个父母。
  • 将 ContextMenu 更改为 DataGrid CM 而不是 DGColumnHeader CM,但它没有帮助。如果这很重要,我会在多个列上使用它..
  • @WPF-如果我们仍然使用ProxyElement,你能解释一下为什么这里需要ContentControl吗? This 解决方案使用类似的方法,但不需要ContentControl
  • @monstr,Freezable 类破解了DataContext ...在我们的例子中,'proxyelement' 不是 Freezable,所以如果它托管在@987654346 中,它可以获得DataContext 的唯一方法@ 如果它是 ContentContentControl,则这是可能的。同样对于链接中的第二个解决方案,NameScoping 没有像DataGridColumnHeaderTemplate 一样在Template 中解析,所以ElementName 不起作用。我提供的解决方案可以解决这两种情况。
猜你喜欢
  • 2018-07-15
  • 2010-12-06
  • 2018-07-28
  • 2015-02-05
  • 2010-12-01
  • 2011-07-17
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多