WPF - 为触发器设置器设置 DataContext
我有一个最近重构的DataTrigger
。它曾经将 DataContext
设置为 ListBoxItem
。现在它是一个ContentPresenter
。
这是代码:
<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>
在 IsCurrentItemEnabledChanged
的 OnChange
中,我可以看到我可以使用以下代码获取 ListBoxItem
(在后面的代码中) ):
listBoxItem = (ListBoxItem)Main.Instance.lstQueryResults.ItemContainerGenerator.
ContainerFromItem(((ContentPresenter)d).Content);
但是,我无法设置 DataContext
,以便我的 IsEnabled
的 Setter
将设置该对象的启用状态ListBoxItem
而不是 ContentPresenter
。
(我会在 IsCurrentItemEnabledChanged
的 OnChange
中执行此操作,但该属性已经有点破解,当触发器设置为错误。)
有什么想法吗?
有人建议我提供更多内容来提供上下文:
这是我的模板 XAML。
<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>
下面是列表框的 XAML:
<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>
DataContext 在代码中设置如下:
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
是一个具有名称-值对和对数据的引用的类(WorkItem
代码>对象)。
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 OnChange
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 OnChange
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).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
抱歉,答案很简短,但您应该将
IsEnabled
的触发器和设置器逻辑移回ListBoxItem
样式:Sorry for the short answer, but you should move the trigger and setter logic for
IsEnabled
back to theListBoxItem
style: