MVVM模式下点击GridView内Edit按钮选中ListView对应项的实现方法
问题修复方案
你现有代码存在4个核心问题,导致点击Edit按钮无法选中对应行、编辑状态切换异常:
ListViewItem.IsSelected属性是bool类型,你错误绑定了BoolToVisibilityConverter(返回Visibility枚举值),类型完全不匹配,绑定直接失效- Edit按钮的
CommandParameter传参错误,传入整个ListViewItems集合没有意义,无法定位当前点击行 User类构造函数中_isEdit默认值写反,初始状态所有行都会进入编辑状态;且单元格内TextBlock未做可见性绑定,编辑状态下文本和输入框会同时显示- 实现思路冗余:不需要手动通过可视化树查找
ListViewItem设置选中状态,利用现有SelectedItem双向绑定就能纯MVVM实现需求
第一步:修正User实体类
把构造函数里的默认IsEdit值改为false,初始加载时所有行默认是浏览状态,其余属性代码保持不变:
public User() { _username = String.Empty; _password = String.Empty; _city = String.Empty; _isEdit = false; // 原代码写的true,改为false } public User(string username, string password, int age, string city) { this._username = username; this._password = password; this._age = age; this._city = city; _isEdit = false; // 原代码写的true,改为false }
第二步:修正XAML绑定
- 删除
ItemContainerStyle中错误的IsSelected属性Setter,选中状态完全由ListView.SelectedItem绑定控制即可 - 给所有列的
TextBlock添加反向可见性绑定:浏览状态显示文本、编辑状态隐藏文本;TextBox保持原有可见性绑定即可 - 修改Edit按钮的
CommandParameter,直接传入当前行绑定的User实体
修正后的核心XAML代码:
<ListView ItemsSource="{Binding List}" Grid.Row="1" SelectionMode="Single" SelectedItem="{Binding SelectedUser, Mode=TwoWay}" x:Uid="Table"> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <!-- 删掉原来错误的IsSelected Setter --> </Style> </ListView.ItemContainerStyle> <ListView.View> <GridView> <GridViewColumn> <GridViewColumnHeader Style="{StaticResource HeaderStyle}"> <ContentControl ContentTemplate="{StaticResource Header}" Content="Username" /> </GridViewColumnHeader> <GridViewColumn.CellTemplate> <DataTemplate> <StackPanel> <!-- 新增TextBlock的反向可见性绑定,IsEdit=false时显示 --> <TextBlock Text="{Binding Username}" Visibility="{Binding IsEdit, Converter={StaticResource BoolToOppositeVisibilityConverter}}"/> <TextBox Text="{Binding Username}" Visibility="{Binding IsEdit, Converter={StaticResource BoolToVisibilityConverter}}" /> </StackPanel> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn> <GridViewColumnHeader Style="{StaticResource HeaderStyle}">Age</GridViewColumnHeader> <GridViewColumn.CellTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Age}" Visibility="{Binding IsEdit, Converter={StaticResource BoolToOppositeVisibilityConverter}}"/> <TextBox Text="{Binding Age}" Visibility="{Binding IsEdit, Converter={StaticResource BoolToVisibilityConverter}}" /> </StackPanel> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn> <GridViewColumnHeader Style="{StaticResource HeaderStyle}">City</GridViewColumnHeader> <GridViewColumn.CellTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding City}" Visibility="{Binding IsEdit, Converter={StaticResource BoolToOppositeVisibilityConverter}}"/> <TextBox Text="{Binding City}" Visibility="{Binding IsEdit, Converter={StaticResource BoolToVisibilityConverter}}" /> </StackPanel> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn> <GridViewColumnHeader Style="{StaticResource HeaderStyle}">Modify</GridViewColumnHeader> <GridViewColumn.CellTemplate> <DataTemplate> <Button Content="Edit" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=DataContext.Edit}" CommandParameter="{Binding}"/> <!-- 直接传当前行绑定的User实体 --> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView>
注:
BoolToOppositeVisibilityConverter是常规布尔转可见性的反向转换器,逻辑为bool值为true时返回Collapsed,false时返回Visible,如果你的项目里没有这个转换器,自行实现即可,也可以通过给现有转换器加ConverterParameter实现反向逻辑。
第三步:实现ViewModel中的Edit命令
命令参数接收当前点击行的User实体,执行逻辑分两步:先给SelectedUser赋值触发ListView选中对应行,再切换编辑状态,全程不需要操作UI控件,完全符合MVVM规范:
// 命令实现根据自己项目使用的MVVM框架调整即可 private ICommand _edit; public ICommand Edit { get { return _edit ??= new RelayCommand<User>((currentUser) => { // 1. 赋值SelectedUser,自动选中对应ListViewItem SelectedUser = currentUser; // 2. 遍历数据源,仅当前行进入编辑状态,其余行退出编辑 foreach (var user in List) { user.IsEdit = user == currentUser; } }); } }
如果需要实现保存/取消编辑的逻辑,只需要在对应命令里把当前SelectedUser的IsEdit属性设为false即可,UI会自动同步状态。
内容的提问来源于stack exchange,提问作者Asucl
相关产品推荐
相关产品推荐

