【问题标题】:Change listbox template on lost focus event in WPF在 WPF 中更改失去焦点事件的列表框模板
【发布时间】:2012-02-24 21:36:28
【问题描述】:

我想展示一个带有 TextBlocks 作为项目的列表框。当用户单击/选择一个项目时,它会变成一个文本框进行编辑。一旦控件失去焦点,项目就会变回 TextBlock。

以下 XAML 几乎可以正常工作,因为 TextBlock 在被选中时确实会变成一个 TextBox。如果我在列表中选择另一个项目,它也会返回到 TextBlock。问题是,如果我移出列表框(在本例中为添加新文本框),列表项将保留为 TextBox。

这个问题 (WPF ListViewItem lost focus event - How to get at the event?) 看起来很有希望,但我做不到。我尝试使用 IsFocused 属性,但后来我无法编辑文本框,因为当我进入文本框时,listboxitem 会失去焦点,因此在我有机会编辑文本之前返回到 TextBlock。

如果列表框/项目失去焦点,如何让 TextBox 转回 TextBlock?

(也欢迎任何其他实现目标的实现)

<Window x:Class="MyView.MainWindow1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        Title="MainWindow1" Height="300" Width="200">
    <Window.Resources>
        <DataTemplate x:Key="ItemTemplate">
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>

        <DataTemplate x:Key="SelectedTemplate">
            <TextBox Text="{Binding Name, Mode=TwoWay}" />
        </DataTemplate>

        <Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
            <Setter Property="ContentTemplate" Value="{StaticResource ItemTemplate}" />
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <StackPanel >
        <ListBox ItemsSource="{Binding Departments}" HorizontalContentAlignment="Stretch"
                 ItemContainerStyle="{StaticResource ContainerStyle}" />
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <TextBox  Text="{Binding NewDepartmentName, Mode=TwoWay}"  />
            <Button Grid.Column="1" Width="50" Content="Add" Command="{Binding Path=AddNewDepartmentCommand}" />
        </Grid>
    </StackPanel>
</Window>

【问题讨论】:

  • 使用 ListBox 上的附加属性来破解它。对项目(以及更改的项目)进行 foreach。锁定每个项目的 Focus 事件/属性,当它发生变化时,使用 VisualTreeHelper 或 LogicalTreeHelper 来查看是否有任何子项(即 TextBox)具有焦点..
  • 我试过这样做,但失败得很惨。能否请您发布一个如何做到这一点的示例?
  • 我刚刚又修改了文本框的外观(Phil 的回答),现在我有了可以使用的东西。谢谢。
  • 你能编辑菲尔对最终结果的回答吗

标签: wpf xaml


【解决方案1】:

这并不能回答您的问题,而是通过在未选择列表框项时使文本框看起来像文本块来提供替代解决方案:

<Page.Resources>
    <ResourceDictionary>
        <Style x:Key="ListBoxSelectableTextBox" TargetType="{x:Type TextBox}">
            <Setter Property="IsHitTestVisible" Value="False" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}" Value="True">
                    <Setter Property="IsHitTestVisible" Value="True" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</Page.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Departments}" HorizontalContentAlignment="Stretch">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBox Margin="5" Style="{StaticResource ListBoxSelectableTextBox}" Text="{Binding Name}" BorderBrush="{x:Null}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

【讨论】:

    【解决方案2】:

    有很多方法可以做到这一点:

    1. 以上答案
    2. 基于 TextBoxBase 创建一个 TextBox 样式,当禁用时,通过设置 BorderThickness="0", Background="transparent" 使 TextBox 看起来像一个 TextBlock
    3. 在每个 ListViewItem 上同时拥有 TextBlock 和 TextBox,并使用上述回答技术隐藏和显示 TextBlock/TextBox 相应

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多