1

I have the following "Style" (defined as a Resource in xaml). This is basically a "DataGridColumnHeaderStyle" with a Menu that implements Row filtering. It is assigned to the DataGrid using: ColumnHeaderStyle="{StaticResource lclDataGridColumnHeaders}"

There are times in Code Behind I need to disable the (row filtering) Menu (menuColumnOptions), which is defined in this Style. Can anyone tell me how to access this element so I can change its Visibility via C#?

I tried: myDataGrid.Template.FindName("menuColumnOptions") but I received an error, something about it must be "applied"...

(I suppose the alternative solution is to create a duplicate "Style" WITHOUT this Menu and change all the Columns to use that style...)

<Style x:Key="lclDataGridColumnHeaders" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Foreground" Value="{StaticResource appTextColor}"/>
<Setter Property="FontWeight" Value="DemiBold"/>
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>

                <Border x:Name="BackgroundBorder"
                        BorderThickness="0,1,0,1" 
                        Background="{StaticResource lclDataGridHeaderBackground}" 
                        BorderBrush="Transparent" 
                        Grid.ColumnSpan="2" />

                <ContentPresenter Margin="6,3,6,3" VerticalAlignment="Center" />

                <Path Grid.Column="1" x:Name="SortArrow" Visibility="Collapsed" Data="M0,0 L1,0 0.5,1 z" 
                        Width="8" Height="6" Fill="Gray" Stretch="Fill" Margin="0,0,8,0"
                        VerticalAlignment="Center" RenderTransformOrigin="0.5,0.4" />


                <Menu Grid.Column="3" x:Name="menuColumnOptions" VerticalAlignment="Center" Background="#FFF9F9F7" HorizontalAlignment="Right" >
                    <MenuItem Padding="0" SubmenuOpened="MenuItemColumnOptions_SubmenuOpened">
                        <MenuItem.Header>
                            <Border BorderBrush="{StaticResource appTextColor}" BorderThickness="1" CornerRadius="2" Height="20" Width="20" >
                                <Path Data="M0,0 L1,0 0.5,1 z" Stretch="Fill" Fill="{StaticResource appTextColor}"
                                        Width="10" Height="8" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.4" Margin="2,0"/>
                            </Border>
                        </MenuItem.Header>
                        <MenuItem x:Name="clearFilterMenuItem" Header="Clear Filter..." Click="ClearFilter_Click" IsEnabled="False">
                            <MenuItem.Icon>
                                <Image Source="/IngramBook.WpfTableEditor;component/Images/edit_undohs.png" Width="16" Height="16"/>
                            </MenuItem.Icon>
                        </MenuItem>
                        <Separator />
                        <MenuItem Header="Equals..." Click="CustomAutoFilter_Click" />
                        <MenuItem Header="Does Not Equal..." Click="CustomAutoFilter_Click"/>
                        <Separator />
                        <MenuItem Header="Begins With..." Click="CustomAutoFilter_Click"/>
                        <MenuItem Header="Ends With..." Click="CustomAutoFilter_Click"/>
                        <Separator />
                        <MenuItem Header="Contains..." Click="CustomAutoFilter_Click" />
                        <MenuItem Header="Does Not Contain..." Click="CustomAutoFilter_Click"/>
                        <Separator />
                        <MenuItem Header="Custom Filter..." Click="CustomAutoFilter_Click">
                            <MenuItem.Icon>
                                <Image Source="/IngramBook.WpfTableEditor;component/Images/Filter2HS.png" Width="16" Height="16"/>
                            </MenuItem.Icon>
                        </MenuItem>
                        <Separator />
                        <MenuItem Header="Select Individual Values..." Click="SelectIndividualItems_Click">
                            <MenuItem.Icon>
                                <Image Source="/IngramBook.WpfTableEditor;component/Images/checkboxhs.png" Width="16" Height="16"/>
                            </MenuItem.Icon>
                        </MenuItem>
                        <Separator />
                        <MenuItem Header="Trim Trailing White Spaces..." Click="TrimTrailingWhiteSpaces_Click"/>
                        <MenuItem Header="Capitalization" >
                            <MenuItem.Icon>
                                <Image Source="/IngramBook.WpfTableEditor;component/Images/FontHS.png" Width="16" Height="16"/>
                            </MenuItem.Icon>
                            <MenuItem Header="Capitalize Each Word" Click="CapitalizeEachWord_Click"/>
                            <MenuItem Header="UPPERCASE" Click="Uppercase_Click"/>
                            <MenuItem Header="lowercase" Click="Lowercase_Click"/>
                        </MenuItem>
                        <Separator />
                        <MenuItem Header="Hide Column" Click="HideColumn_Click"/>
                        <Separator />
                        <MenuItem x:Name="deleteColumnMenuItem" Header="Delete Column" Click="dropColumnButton_Click">
                            <MenuItem.Icon>
                                <Image Source="/IngramBook.WpfTableEditor;component/Images/DeleteHS.png" Width="16" Height="16"/>
                            </MenuItem.Icon>
                        </MenuItem>
                    </MenuItem>
                </Menu>

                <Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                <Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="SortDirection" Value="Ascending">
                    <Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
                    <Setter TargetName="SortArrow" Property="RenderTransform">
                        <Setter.Value>
                            <RotateTransform Angle="180" />
                        </Setter.Value>
                    </Setter>
                </Trigger>
                <Trigger Property="SortDirection" Value="Descending">
                    <Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
                </Trigger>
                <Trigger Property="SortDirection" Value="{x:Null}">
                    <Setter TargetName="SortArrow" Property="Visibility" Value="Collapsed" />
                </Trigger>
                <Trigger Property="DisplayIndex" Value="0">
                    <Setter Property="Visibility" Value="Collapsed" TargetName="PART_LeftHeaderGripper" />
                </Trigger>
                <Trigger Property="IsMouseOver" Value="True" >
                    <Setter Property="Background" TargetName="BackgroundBorder" Value="{StaticResource appButtonBackgroundHighlight}" />
                    <Setter Property="BorderBrush" TargetName="BackgroundBorder" Value="Transparent" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>

Shayne
  • 1,083
  • 3
  • 18
  • 30

2 Answers2

0

Would you be able to create an attached property (of tybe boolean or visibility) for the DataGridColumnHeader class and bind the Enabled or Visibility property of your Menu to that attached property?

http://www.deepcode.co.uk/2008/08/exposing-new-properties-for-control_15.html

Edit:

My thought is that an attached property is going to be simpler as you could just set the visibility in XAML, but I tried a quick test and I think the method you are trying to use should work just as well.
Menu myMenu = (Menu)this.myDataGrid.Template.FindName("menuColumnOptions", this.myDataGrid);
menu.Visibility = System.Windows.Visibility.Hidden;

If you're getting an error, could you show the code where you are trying to set the visibility in code behind? It sounds like you might be trying to access the DataGridColumnHeader's Template before it's been fully constructed (in which case moving your code to the Loaded event might solve your problem).

Edit 2:

<Window x:Class="TestApp11.MainWindow" 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:l="clr-namespace:TestApp11"
  xmlns:s="clr-namespace:System;assembly=mscorlib"
  Title="Window1" Height="500" Width="800">
    <Grid>
        <Grid.Resources>
            <Style x:Key="MyButtonStyle" TargetType="Button">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border BorderBrush="Red" BorderThickness="2">
                                <StackPanel>
                                    <TextBlock x:Name="MyTextBlock" Text="Control Template's TextBlock 1" />
                                    <ContentPresenter />
                                    <TextBlock Text="Control Template's TextBlock 2" />
                                </StackPanel>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Button x:Name="scottsButton" Style="{StaticResource MyButtonStyle}">
            <TextBlock Text="This Text should appear where the Control Template's ContentPresenter is located."/>
        </Button>
        <Button Grid.Row="1" Content="Click to hide visibility of TextBlock1" Click="Button_Click" />
    </Grid>
</Window>

Code Behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        TextBlock tb = (TextBlock)this.scottsButton.Template.FindName("MyTextBlock", this.scottsButton);
        tb.Visibility = System.Windows.Visibility.Hidden;
    }
}
Scott
  • 11,840
  • 6
  • 47
  • 54
  • I suppose. I am just not quite sure "how"? I was hoping I could just get to the Visibility property from the Menu element (x:Name="menuColumnOptions"). Wouldn't that be the simplest method? (If it is possible...) – Shayne Mar 15 '11 at 14:02
  • @Shayne, I'll leave it up to you to determine what the simplest method is for your scenario, but I believe you should be able to do use Template.FindName(...) as you suggest in your question. I tried a quick test with a ControlTemplate for a Button set in a Resource Style. Then in a different button's click event handler, I was able to access a named TextBlock within my ControlTemplate and change it's Text. I've edited my answer to use the exact lines of code I think you'd need to use so hopefully that helps! – Scott Mar 15 '11 at 18:20
  • I am trying to "hide" it in the handler for a Button Click Event. Unfortunately, the FindName method returns a NULL. I would be happy to try your other suggestion, but this is the first WPF application I have ever worked on and I wouldn't know where to begin. Any idea why it would be null at this point? The difference between my situation and your test, is this Style is assigned to the DataGrid statically via the "ColumnHeaderStyle" property as I noted in my original post, but I don't see why that would matter (although, it must)??? – Shayne Mar 16 '11 at 17:35
  • Now that I consider my last sentence. Of course it matters, this Style/Menu must be assigned to EVERY Column Header, right? So, I am going to have to change it on every Column (for each?).... am I headed in the right direction? – Shayne Mar 16 '11 at 17:43
  • @Scott Do I need to take an approach similar to this? http://stackoverflow.com/questions/4030764/how-to-get-datagridcolumnheader-from-datagridcolumn – Shayne Mar 16 '11 at 19:35
  • @Shayne, Ahhh... I think I see what you're getting at. Your original post is attempting to access a control within your DataGridColumnHeader's template... but it's null because you're trying to get it from the template of your DataGrid, not your DataGridColumnHeader's template. And yeah, you're right... if you want to do it in codebehind... you'll have to do it for each Column's ColumnHeader! – Scott Mar 16 '11 at 19:50
  • And yeah... it looks like you might have to do something similar to that StackOverflow answer to get access to each ColumnHeader (so you can access it's template). – Scott Mar 16 '11 at 19:55
0

Here is what I ended up doing.

I copied the Style and removed the Menu from this Copy.

Then, in code I just set it using:

myDataGrid.ColumnHeaderStyle = (Style)FindResource("lclDataGridLockedColumnHeaders");

Shayne
  • 1,083
  • 3
  • 18
  • 30