views:

606

answers:

1

I have a DataTrigger that I recently refactored. It used to have the "DataContext" set to be a ListBoxItem. Now it is a ContentPresenter.

Here is the code:

<DataTemplate.Triggers>
    <DataTrigger Value="True">
        <DataTrigger.Binding>
            <MultiBinding Converter="{StaticResource DisableWorkItemConverter}">
                <Binding ElementName="MainForm" Path="PickedWorkItemID"/>
                <Binding Path="WorkItemForColumn.Id"/>
            </MultiBinding>
        </DataTrigger.Binding>
        <Setter Property="IsEnabled" Value="False"/>
        <Setter Property="loc:Main.IsCurrentItemEnabledChanged" Value="True"/>
    </DataTrigger>
</DataTemplate.Triggers>

In the On Change of IsCurrentItemEnabledChanged I can see that I can get at the ListBoxItem with the following code (in the code behind):

listBoxItem = (ListBoxItem)Main.Instance.lstQueryResults.ItemContainerGenerator.
               ContainerFromItem(((ContentPresenter)d).Content);

However, there is no way that I can see to set the DataContext such that my Setter for IsEnabled will set the enabled status of the ListBoxItem rather than the ContentPresenter.

(I would do it in the On Change of IsCurrentItemEnabledChanged, but that property is already a bit of a hack and it will not re-enable the item when the trigger is set to false.)

Any ideas?


It was suggested that I provide more to provide context:

Here is my XAML for the templates.

<DataTemplate x:Key="ColumnTemplate">
    <Border Name="ItemBorder" BorderBrush="Black" BorderThickness="1" CornerRadius="2" Padding="2">
        <WrapPanel>                   
            <TextBlock Margin="0,0,5,0">
                <TextBlock.Text>
                    <Binding Path="Name" Converter="{StaticResource GetVisibilityOfColumnTitles}"/>
                </TextBlock.Text>
            </TextBlock>
            <TextBlock Text="{Binding Value}" Margin="0,0,10,0" FontWeight="Bold" />
        </WrapPanel>
    </Border>
</DataTemplate>

<DataTemplate x:Key="RowTemplate">
    <Border x:Name="ItemBorder" BorderThickness="1" BorderBrush="#D4D4FF">
        <Grid x:Name="ItemGrid" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsPresenter}}, Path=ActualWidth}" ScrollViewer.CanContentScroll="True" Margin="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="30" />
            </Grid.ColumnDefinitions>
            <Grid.Background>
                <Binding Path="WorkItemForColumn.Type" Converter="{StaticResource WorkItemTypeToColorConverter}" />
            </Grid.Background>

            <CheckBox VerticalAlignment="Center" Grid.Column="0" IsChecked="{Binding
                                      RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}},
                                      Mode=TwoWay, Path=IsSelected}" Name="chkIsSelected" />

            <ItemsControl Grid.Column="1" Margin="5,0,5,0" ItemsSource="{Binding}" ItemTemplate="{StaticResource ColumnTemplate}" >
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Horizontal"></WrapPanel>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>


            <Button HorizontalAlignment="Right" x:Name="btnPick" Grid.Column="3" Style="{StaticResource roundButton}" Width="15" Height="15" Tag="{Binding WorkItemForColumn.Id}" Margin="5,0,10,0">
                <Path Fill="DarkBlue">
                    <Path.Data>
                        <PathGeometry>
                            <PathFigure StartPoint="2,0" IsClosed="True">
                                <LineSegment Point="7,5"/>
                                <LineSegment Point="2,10"/>
                            </PathFigure>
                            <PathFigure StartPoint="2,2" IsClosed="True">
                                <LineSegment Point="5,5"/>
                                <LineSegment Point="2,8"/>
                            </PathFigure>
                        </PathGeometry>
                    </Path.Data>
                </Path>
            </Button>
        </Grid>
    </Border>
    <DataTemplate.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <MultiBinding Converter="{StaticResource DisableWorkItemConverter}">
                    <Binding ElementName="MainForm" Path="PickedWorkItemID"/>
                    <Binding Path="WorkItemForColumn.Id"/>
                </MultiBinding>
            </DataTrigger.Binding>
            <Setter Property="IsEnabled" Value="False"/>
            <Setter Property="loc:Main.IsCurrentItemEnabledChanged" Value="True"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

Here is the XAML for the List Box:

<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled" Button.Click="PickWorkItem_Click" SelectionMode="Multiple" ItemTemplate="{StaticResource RowTemplate}"  Name="lstQueryResults" SelectionChanged="lstQueryResults_SelectionChanged" >
    <ListBox.Resources>
        <Style TargetType="{x:Type ListBoxItem}">
            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/>
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black"/>
            </Style.Resources>
        </Style>
    </ListBox.Resources>
</ListBox>

The DataContext is set in the Code like so:

private void ChangeQueryResultListSource(WorkItemCollection queryResults, bool b)
{
    // Un-hook the selection event while we change the ItemsSource
    Form.ToggleOnSelectEvent(false);

    // This sets the DataContext
    QueryDisplay = GetDisplayValues(queryResults);

    Form.QueryResultListSource = QueryDisplay;
    // Rewire the selection events back in
    Form.ToggleOnSelectEvent(true);


    foreach (WorkItem item in Pad.Keys)
    {
        Form.SelectQueryResultItem(item);
    }
}

private List<List<WorkItemColumn>> GetDisplayValues(WorkItemCollection queryResults)
{
    var result = new List<List<WorkItemColumn>>();
    foreach (WorkItem workItem in queryResults)
    {
        var row = GetQueryColumns(queryResults.DisplayFields, workItem);
        result.Add(row);
    }
    return result;
}

private List<WorkItemColumn> GetQueryColumns(DisplayFieldList fields, WorkItem workItem)
{
    var row = new List<WorkItemColumn>();
    foreach (FieldDefinition column in fields)
    {
        var workItemColumn = new WorkItemColumn { Name = column.Name, Value = workItem[column.Name], WorkItemForColumn = workItem };
        row.Add(workItemColumn);
    }

    return row;
}

WorkItemColumn is a class with a Name-Value pair and a reference to the data (a WorkItem object).

+1  A: 

Sorry for the short answer, but you should move the trigger and setter logic for IsEnabled back to the ListBoxItem style:

<Style TargetType="{x:Type ListBoxItem}">
    <Style.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/>
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black"/>
    </Style.Resources>
    <Style.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <MultiBinding Converter="{StaticResource DisableWorkItemConverter}">
                    <Binding ElementName="MainForm" Path="PickedWorkItemID"/>
                    <Binding Path="WorkItemForColumn.Id"/>
                </MultiBinding>
            </DataTrigger.Binding>
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </Style.Triggers>
</Style>
Aviad P.
Thanks!! That did it!
Vaccano