如果单击数据模板中的控件,如何选择ListView行

发布于 2024-10-21 08:11:15 字数 8979 浏览 1 评论 0原文

我有一个使用 DataTemplate 的 ListView。我根据特定项目的 IsSelected 属性交换项目数据模板。这允许我显示编辑模板和读取模板。 ListView 包含两列。在读取模式下,两列是只读文本框,在编辑模式下,左列是可编辑文本框,右列是下拉菜单。只要我在阅读模式下不直接单击其中一个文本框,一切都会很好。如果我在控件外部单击,则可以很好地选择该行,但是在控件内部单击时,不会选择该行。这会阻止我在单击其中一个单元格时进入编辑模式。

我已将我的 xaml 粘贴在下面。您可以看到 GridBlock 和 GridEdit 样式将由 ListView 的 IsSelected 属性控制。这就是我可以根据该 DP 交换 DataTemplate(真正隐藏或折叠)的原因。我进一步专门化了这些样式,以便在值为空且控件没有焦点时允许带水印的文本框。我认为这就是我的问题所在,但就我的一生而言,我想不出一种方法来声明性地做到这一点。另外,我是 WPF 新手,所以我确信这类事情有一个模式,只是很难制定一个从 google 或 bing 返回有意义的结果的查询。提前感谢您的任何和所有帮助。

这是我的样式和数据模板:

<Style TargetType="{x:Type FrameworkElement}" x:Key="GridBlockStyle">
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Visibility" 
            Value="{Binding Path=IsSelected, 
                    RelativeSource={RelativeSource FindAncestor, 
                    AncestorType={x:Type ListViewItem}},
                    Converter={StaticResource boolToVis}, 
                    ConverterParameter=False}" />
</Style>

<Style TargetType="{x:Type FrameworkElement}" x:Key="GridEditStyle">
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Visibility" 
            Value="{Binding Path=IsSelected, 
                    RelativeSource={RelativeSource FindAncestor, 
                    AncestorType={x:Type ListViewItem}},
                    Converter={StaticResource boolToVis}, 
                    ConverterParameter=True}" />
</Style>
<Style x:Key="TextBoxReadOnly" TargetType="{x:Type TextBox}" BasedOn="{StaticResource GridBlockStyle}">
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
    <Setter Property="AllowDrop" Value="true" />
    <Setter Property="Background" Value="Transparent"></Setter>
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Stretch" />
    <Setter Property="Padding" Value="8,5,3,3" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Grid>
                    <Label x:Name="TextPrompt" Content="{TemplateBinding Tag}" Visibility="Collapsed" Focusable="False"  Foreground="Silver"></Label>
                    <ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="{DynamicResource OutsideFontColor}" />
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsFocused" Value="False"></Condition>
                            <Condition Property="Text" Value=""></Condition>
                        </MultiTrigger.Conditions>
                        <MultiTrigger.Setters>
                            <Setter Property="Visibility" TargetName="TextPrompt" Value="Visible"></Setter>
                        </MultiTrigger.Setters>
                    </MultiTrigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="DimGray" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="TextBoxEditable" TargetType="{x:Type TextBox}" BasedOn="{StaticResource GridEditStyle}">
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
    <Setter Property="AllowDrop" Value="true" />
    <Setter Property="Background" Value="Transparent"></Setter>
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Stretch" />
    <Setter Property="Padding" Value="8,5,3,3" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Grid>
                    <Border x:Name="BorderBase" Background="White" BorderThickness="1.4,1.4,1,1" 
                    BorderBrush="Silver" />
                    <Label x:Name="TextPrompt" Content="{TemplateBinding Tag}" Visibility="Collapsed" Focusable="False"  Foreground="Silver"></Label>
                    <ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="{DynamicResource OutsideFontColor}" />
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsFocused" Value="False"></Condition>
                            <Condition Property="Text" Value=""></Condition>
                        </MultiTrigger.Conditions>
                        <MultiTrigger.Setters>
                            <Setter Property="Visibility" TargetName="TextPrompt" Value="Visible"></Setter>
                        </MultiTrigger.Setters>
                    </MultiTrigger>
                    <Trigger Property="IsFocused" Value="True">
                        <Setter Property="BorderThickness" TargetName="BorderBase" Value="2.4,2.4,1,1"></Setter>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="DimGray" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这是我的 ListView 视图:

<ListView.View>
    <GridView>

    <GridViewColumn Width="120">
        <GridViewColumnHeader Content="Resource ID" />
        <GridViewColumn.CellTemplate>
        <DataTemplate>
            <Grid>
            <TextBox Margin="3" Tag="Enter Resource ID" Text="{Binding Path=ResourceID, UpdateSourceTrigger=PropertyChanged}"
                    Style="{StaticResource TextBoxReadOnly}" IsReadOnly="True" />
            <TextBox Width="90" Tag="Enter Resource ID"  Margin="3"
                 Style="{StaticResource TextBoxEditable}" Text="{Binding Path=ResourceID, UpdateSourceTrigger=PropertyChanged}" />
            </Grid>
        </DataTemplate>
        </GridViewColumn.CellTemplate>
    </GridViewColumn>

    <GridViewColumn Width="120">
        <GridViewColumnHeader Content="Code" />
        <GridViewColumn.CellTemplate>
        <DataTemplate>
            <Grid>
            <TextBox Margin="3" Tag="Enter Code" Text="{Binding Path=Code}"
                    Style="{StaticResource TextBoxReadOnly}" IsReadOnly="True" />
            <ComboBox Margin="3" Style="{StaticResource GridEditStyle}" 
                  ItemsSource="{Binding Source={StaticResource CodeViewSource}, Mode=OneWay}"
                  SelectedItem="{Binding Path=Code, Mode=TwoWay}"
                  IsSynchronizedWithCurrentItem="False"
                  util:ComboBoxWidthFromItemsBehavior.ComboBoxWidthFromItems="True" />
            </Grid>
        </DataTemplate>
        </GridViewColumn.CellTemplate>
    </GridViewColumn>

    <GridViewColumn Width="120">
        <GridViewColumn.CellTemplate>
        <DataTemplate>
            <Button Margin="5" Content="Delete" 
                Command="{Binding Path=DataContext.RemoveORIEntryCommand,
                RelativeSource={RelativeSource FindAncestor, 
                AncestorType={x:Type UserControl}}}">
            <Button.Resources>
                <Converter:AgencyItemIDParametersConverter x:Key="RemoveListViewItemParametersConverter" />
            </Button.Resources>
            <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource RemoveListViewItemParametersConverter}">
                <MultiBinding.Bindings>
                    <Binding Path="AgencyID" />
                    <Binding Path="ID" />
                </MultiBinding.Bindings>
                </MultiBinding>
            </Button.CommandParameter>
            </Button>
        </DataTemplate>
        </GridViewColumn.CellTemplate>                                                   
    </GridViewColumn>
    </GridView>                                            
</ListView.View>

I have a ListView that is using a DataTemplate. I swap out the Item DataTemplate based on the IsSelected property of the particular item. This allows me to display an edit template and a read template. The ListView contains two columns. In read mode the two columns are readonly TextBoxes and in edit mode the left column is a editable TextBox and the right column is a drop down. Everything works great as long as I don't click directly on one of the TextBoxes when in read mode. If I click outside the control the row is selected just fine, when selecting inside the control, however, the row is not selected. This prevents me from entering edit mode when one of the cells are clicked.

I've pasted my xaml below. You can see that the GridBlock and GridEdit styles will be controlled by the IsSelected property of the ListView. This is what allows me to swap out the DataTemplate (really hide or collapse) based on that DP. I've further specialized these styles to allow for watermarked textboxes when the value is empty and the control doesn't have focus. I think this is where my problem lies but for the life of me I can't think of a way to do this declaratively. Also, I'm new to WPF so I'm sure there is a pattern for this sort of thing it's just very difficult to formulate a query that will return meaningful results from google or bing. Thanks for any and all help in advance.

Here are my styles and datatemplates:

<Style TargetType="{x:Type FrameworkElement}" x:Key="GridBlockStyle">
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Visibility" 
            Value="{Binding Path=IsSelected, 
                    RelativeSource={RelativeSource FindAncestor, 
                    AncestorType={x:Type ListViewItem}},
                    Converter={StaticResource boolToVis}, 
                    ConverterParameter=False}" />
</Style>

<Style TargetType="{x:Type FrameworkElement}" x:Key="GridEditStyle">
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Visibility" 
            Value="{Binding Path=IsSelected, 
                    RelativeSource={RelativeSource FindAncestor, 
                    AncestorType={x:Type ListViewItem}},
                    Converter={StaticResource boolToVis}, 
                    ConverterParameter=True}" />
</Style>
<Style x:Key="TextBoxReadOnly" TargetType="{x:Type TextBox}" BasedOn="{StaticResource GridBlockStyle}">
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
    <Setter Property="AllowDrop" Value="true" />
    <Setter Property="Background" Value="Transparent"></Setter>
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Stretch" />
    <Setter Property="Padding" Value="8,5,3,3" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Grid>
                    <Label x:Name="TextPrompt" Content="{TemplateBinding Tag}" Visibility="Collapsed" Focusable="False"  Foreground="Silver"></Label>
                    <ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="{DynamicResource OutsideFontColor}" />
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsFocused" Value="False"></Condition>
                            <Condition Property="Text" Value=""></Condition>
                        </MultiTrigger.Conditions>
                        <MultiTrigger.Setters>
                            <Setter Property="Visibility" TargetName="TextPrompt" Value="Visible"></Setter>
                        </MultiTrigger.Setters>
                    </MultiTrigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="DimGray" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="TextBoxEditable" TargetType="{x:Type TextBox}" BasedOn="{StaticResource GridEditStyle}">
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
    <Setter Property="AllowDrop" Value="true" />
    <Setter Property="Background" Value="Transparent"></Setter>
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Stretch" />
    <Setter Property="Padding" Value="8,5,3,3" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Grid>
                    <Border x:Name="BorderBase" Background="White" BorderThickness="1.4,1.4,1,1" 
                    BorderBrush="Silver" />
                    <Label x:Name="TextPrompt" Content="{TemplateBinding Tag}" Visibility="Collapsed" Focusable="False"  Foreground="Silver"></Label>
                    <ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="{DynamicResource OutsideFontColor}" />
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsFocused" Value="False"></Condition>
                            <Condition Property="Text" Value=""></Condition>
                        </MultiTrigger.Conditions>
                        <MultiTrigger.Setters>
                            <Setter Property="Visibility" TargetName="TextPrompt" Value="Visible"></Setter>
                        </MultiTrigger.Setters>
                    </MultiTrigger>
                    <Trigger Property="IsFocused" Value="True">
                        <Setter Property="BorderThickness" TargetName="BorderBase" Value="2.4,2.4,1,1"></Setter>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="DimGray" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And here is my ListView view:

<ListView.View>
    <GridView>

    <GridViewColumn Width="120">
        <GridViewColumnHeader Content="Resource ID" />
        <GridViewColumn.CellTemplate>
        <DataTemplate>
            <Grid>
            <TextBox Margin="3" Tag="Enter Resource ID" Text="{Binding Path=ResourceID, UpdateSourceTrigger=PropertyChanged}"
                    Style="{StaticResource TextBoxReadOnly}" IsReadOnly="True" />
            <TextBox Width="90" Tag="Enter Resource ID"  Margin="3"
                 Style="{StaticResource TextBoxEditable}" Text="{Binding Path=ResourceID, UpdateSourceTrigger=PropertyChanged}" />
            </Grid>
        </DataTemplate>
        </GridViewColumn.CellTemplate>
    </GridViewColumn>

    <GridViewColumn Width="120">
        <GridViewColumnHeader Content="Code" />
        <GridViewColumn.CellTemplate>
        <DataTemplate>
            <Grid>
            <TextBox Margin="3" Tag="Enter Code" Text="{Binding Path=Code}"
                    Style="{StaticResource TextBoxReadOnly}" IsReadOnly="True" />
            <ComboBox Margin="3" Style="{StaticResource GridEditStyle}" 
                  ItemsSource="{Binding Source={StaticResource CodeViewSource}, Mode=OneWay}"
                  SelectedItem="{Binding Path=Code, Mode=TwoWay}"
                  IsSynchronizedWithCurrentItem="False"
                  util:ComboBoxWidthFromItemsBehavior.ComboBoxWidthFromItems="True" />
            </Grid>
        </DataTemplate>
        </GridViewColumn.CellTemplate>
    </GridViewColumn>

    <GridViewColumn Width="120">
        <GridViewColumn.CellTemplate>
        <DataTemplate>
            <Button Margin="5" Content="Delete" 
                Command="{Binding Path=DataContext.RemoveORIEntryCommand,
                RelativeSource={RelativeSource FindAncestor, 
                AncestorType={x:Type UserControl}}}">
            <Button.Resources>
                <Converter:AgencyItemIDParametersConverter x:Key="RemoveListViewItemParametersConverter" />
            </Button.Resources>
            <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource RemoveListViewItemParametersConverter}">
                <MultiBinding.Bindings>
                    <Binding Path="AgencyID" />
                    <Binding Path="ID" />
                </MultiBinding.Bindings>
                </MultiBinding>
            </Button.CommandParameter>
            </Button>
        </DataTemplate>
        </GridViewColumn.CellTemplate>                                                   
    </GridViewColumn>
    </GridView>                                            
</ListView.View>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

画离情绘悲伤 2024-10-28 08:11:15

我在 ListView 中遇到了类似的问题。

基本上 ListView 的每个项目都有一个 RadioButton 和一个 TextBox。 RadioButton IsChecked 属性已绑定到 ListViewItem 选择属性。问题是,当我选择 TextBox 时,未选择该项目,因此未检查 RadioButton。

我设法使用 IsKeyboardFocusWithin 属性解决了该问题。我在 ListViewItem 样式中设置了一个触发器,因此当此属性为 true 时,isSelected 属性也将设置为 true。

您可以查看此线程

I had a similar problem in a ListView.

Basically each item of the ListView had a RadioButton and a TextBox. The RadioButton IsChecked property was binded to the ListViewItem select property. The thing was that when I selected the TextBox the item was not selected, hence not checking the RadioButton.

I managed to solve the problem with the IsKeyboardFocusWithin property. I set a trigger in the ListViewItem style so when this property is true the isSelected property would be set to true also.

You can check this thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文