【问题标题】:SelectedRow of datagrid is not selected again after returning to same Page返回同一页面后未再次选择数据网格的SelectedRow
【发布时间】:2014-08-26 09:21:26
【问题描述】:

我有两个不同的页面,分别称为 Select 和 Edit。它们都共享同一个 ViewModel,名为 SalesAccountsViewModel。

我在选择页面中有一个 DataGrid,如下所示:

然后我从 DataGrid 中选择任何项目:

然后我点击所选行上的编辑按钮,如下所示:

之后我被重定向到另一个页面,如下所示:

当我点击保存按钮时:

我再次被重定向到上一页,但您能看到第一行吗?它没有完全突出显示:

这是我使用的选择页面:

<Page x:Class="MiniAccountWPF.Views.Pages.Masters.SalesAccounts.Select"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:vm="clr-namespace:MiniAccountWPF.ViewModels.Masters"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="Select" DataContext="{StaticResource salesAccountsViewModel}">

    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Button Grid.Row="0" Margin="0,10" HorizontalAlignment="Left" 
                Content="{Binding SelectedChildMenuItem.MenuItemName, Converter={StaticResource createButtonContentConverter}, Source={StaticResource mainWindowViewModel}}" />

        <DataGrid Grid.Row="1" ItemsSource="{Binding Ledgers}" SelectedValue="{Binding SelectedLedger}" 
                  IsReadOnly="True" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Customer Name" Binding="{Binding LedgerName}" />
                <DataGridTextColumn Header="City" Binding="{Binding City}" />
                <DataGridTemplateColumn Header="Mobile Numbers">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock>
                                    <Run Text="{Binding MobileNo1, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=N}" />
                                    <Run Text="{Binding MobileNo1, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=S}" FontFamily="Consolas"/>
                                    <Run Text="   " FontFamily="Consolas"/>
                                    <Run Text="{Binding MobileNo2, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=N}" />
                                    <Run Text="{Binding MobileNo2, Converter={StaticResource mobileNumberFormatConverter}, ConverterParameter=S}" FontFamily="Consolas"/>
                            </TextBlock>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="Opening Balance" Binding="{Binding OpeningBalance}" />
                <DataGridTemplateColumn Header="Edit">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="Edit" Style="{StaticResource EditButton}" 
                                    Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Delete">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="Delete" Style="{StaticResource DeleteButton}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

    </Grid>

</Page>

这里是编辑页面:

<Page x:Class="MiniAccountWPF.Views.Pages.Masters.SalesAccounts.Edit"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:vm="clr-namespace:MiniAccountWPF.ViewModels.Masters"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="Edit" DataContext="{StaticResource salesAccountsViewModel}">

    <Grid DataContext="{Binding SelectedLedger}">
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="10" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="10" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="10" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="10" />
            <RowDefinition Height="30" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="20" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="350" />
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Row="1" Grid.Column="1" Text="Name" Style="{StaticResource txtBlock}"/>
        <TextBlock Grid.Row="1" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
        <TextBox Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="3" Text="{Binding LedgerName}"/>

        <TextBlock Grid.Row="3" Grid.Column="1" Text="City" Style="{StaticResource txtBlock}"/>
        <TextBlock Grid.Row="3" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
        <TextBox Grid.Row="3" Grid.Column="2" Text="{Binding City}"/>

        <TextBlock Grid.Row="5" Grid.Column="1" Text="Mobile No." Style="{StaticResource txtBlock}"/>
        <TextBlock Grid.Row="5" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
        <TextBox Grid.Row="5" Grid.Column="2" Text="{Binding MobileNo1}"/>
        <TextBox Grid.Row="5" Grid.Column="4" Text="{Binding MobileNo2}"/>

        <TextBlock Grid.Row="7" Grid.Column="1" Text="Opening Balance    " Style="{StaticResource txtBlock}"/>
        <TextBlock Grid.Row="7" Grid.Column="1" Text=" : " HorizontalAlignment="Right" Style="{StaticResource txtBlock}"/>
        <TextBox Grid.Row="7" Grid.Column="2" Text="{Binding OpeningBalance}"/>

        <Grid Grid.Row="10" Grid.Column="4">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="10" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Button Grid.Column="1" Content="Save" 
                    Command="{Binding DataContext.EditSaveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"/>
            <Button Grid.Column="3" Content="Cancel" HorizontalAlignment="Left" 
                    Command="{Binding DataContext.EditCancelCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"/>

        </Grid>

    </Grid>

</Page>

视图模型:

namespace MiniAccountWPF.ViewModels.Masters
{
    public class SalesAccountsViewModel: ViewModelBase, IModule
    {
        public SalesAccountsViewModel()
        {

            SessionViewModel.Instance.ModulesOpen.Add((IModule)this);

            using (MiniAccountDBEntities db = new MiniAccountDBEntities())
            {
                Ledgers = new ObservableCollection<Ledger>(db.Ledgers.Where(x => x.LedgerType.LedgerTypeName == "Customer"));
            }

            EditCommand = new RelayCommand(Edit_Click);
            EditSaveCommand = new RelayCommand(Edit_Save_Click);
            EditCancelCommand = new RelayCommand(Edit_Cancel_Click);
        }

        ~SalesAccountsViewModel()
        {
            SessionViewModel.Instance.ModulesOpen.Remove((IModule)this);
        }

        private ObservableCollection<Ledger> _ledgers;
        public ObservableCollection<Ledger> Ledgers
        {
            get
            {
                return _ledgers;
            }
            set
            {
                _ledgers = value;
                OnPropertyChanged("Ledgers");
            }
        }

        private Ledger _selectedLedger;
        public Ledger SelectedLedger
        {
            get
            {
                return _selectedLedger;
            }
            set
            {
                _selectedLedger = value;
                OnPropertyChanged("SelectedLedger");
            }
        }

        public ICommand EditCommand { get; set; }

        private void Edit_Click(object obj)
        {
            var mainWindowVM = SessionViewModel.GetModuleInstance("MainWindow", "MiniAccountWPF.ViewModels.MainWindowViewModel");
            ((MainWindowViewModel)mainWindowVM).InnerSourcePage = ((MainWindowViewModel)mainWindowVM).SelectedChildMenuItem.EditFrameNavigationURL;
        }

        public ICommand EditSaveCommand { get; set; }

        private void Edit_Save_Click(object obj)
        {
            using (MiniAccountDBEntities db = new MiniAccountDBEntities())
            {
                Ledger ledger = db.Ledgers.Single(x => x.LedgerID == SelectedLedger.LedgerID);
                ledger.LedgerName = SelectedLedger.LedgerName;
                ledger.City = SelectedLedger.City;
                ledger.MobileNo1 = SelectedLedger.MobileNo1;
                ledger.MobileNo2 = SelectedLedger.MobileNo2;
                ledger.OpeningBalance = SelectedLedger.OpeningBalance;
                db.SaveChanges();

                var mainWindowVM = SessionViewModel.GetModuleInstance("MainWindow", "MiniAccountWPF.ViewModels.MainWindowViewModel");
                ((MainWindowViewModel)mainWindowVM).InnerSourcePage = ((MainWindowViewModel)mainWindowVM).SelectedChildMenuItem.SelectFrameNavigationURL;
            }
        }

        public ICommand EditCancelCommand { get; set; }

        private void Edit_Cancel_Click(object obj)
        {
                var mainWindowVM = SessionViewModel.GetModuleInstance("MainWindow", "MiniAccountWPF.ViewModels.MainWindowViewModel");
                ((MainWindowViewModel)mainWindowVM).InnerSourcePage = ((MainWindowViewModel)mainWindowVM).SelectedChildMenuItem.SelectFrameNavigationURL;
        }

        public string ModuleFriendlyName
        {
            get { return "SalesAccountsViewModel"; }
        }

        public string ModuleName
        {
            get { return "SalesAccounts"; }
        }
    }
}

ResourceDictionary 中应用于 DataGrid 的样式:

<Style TargetType="{x:Type DataGrid}">
    <Setter Property="GridLinesVisibility" Value="Vertical" />
    <Setter Property="RowHeaderWidth" Value="0" />
</Style>

<Style TargetType="{x:Type DataGridColumnHeader}">
    <Setter Property="Background" Value="{StaticResource BrushHeaderBackground}" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="Padding" Value="10" />
    <Setter Property="FontSize" Value="16" />
    <Setter Property="FontWeight" Value="SemiBold" />
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="BorderBrush" Value="White" />
    <Setter Property="BorderThickness" Value="1,0" />

    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsMouseOver" Value="True" />
                <Condition Property="CanUserSort" Value="True" />
            </MultiTrigger.Conditions>
            <MultiTrigger.Setters>
                <Setter Property="Background" Value="{StaticResource BrushOrangeSelector}" />
            </MultiTrigger.Setters>
        </MultiTrigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsPressed" Value="True" />
                <Condition Property="CanUserSort" Value="True" />
            </MultiTrigger.Conditions>
            <MultiTrigger.Setters>
                <Setter Property="Background" Value="{StaticResource BrushBlueSelector}" />
            </MultiTrigger.Setters>
        </MultiTrigger>
    </Style.Triggers>
</Style>

<Style TargetType="{x:Type DataGridCell}">

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <Grid Background="{TemplateBinding Background}">
                    <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="Background" Value="Gray" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="Padding" Value="10" />
    <Setter Property="FontSize" Value="16" />

    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="{StaticResource BrushBlueSelector}" />
        </Trigger>
    </Style.Triggers>

</Style>

<Style TargetType='{x:Type DataGridRow}'>
    <Setter Property="Background" Value="Gray" />
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="{StaticResource BrushBlueSelector}" />
        </Trigger>
    </Style.Triggers>
</Style>

【问题讨论】:

  • 为什么不能重新选择?
  • 如何重新选择它?
  • 数据绑定一个对象到DataGrid.SelectedItem属性(&lt;DataGrid SelectedItem="{Binding SelectedItem}" ... /&gt;)然后调用:SelectedItem = someItemFromDataBoundItemsSource;
  • 我已经将 DataGrid 的 SelectedValue 绑定到一个名为 SelectedLedger 的属性。
  • SelectedValueSelectedItem 属性完全不同,因为它返回一个属性值,而不是一个对象。尝试改用SelectedItem 属性。

标签: c# wpf datagrid


【解决方案1】:

问题在于视图模型,每个视图都会创建该模型,从而导致人员集合的多个副本

所以我确实在单个实例的 ServiceLocator 中为 VM 放置了一个属性并初始化了它

public ListViewModel ListViewModel {get; set;}

然后我将列表视图中的视图模型声明替换为指向该属性

DataContext="{Binding ListViewModel, Source={x:Static vm:ServiceLocator.Instance}}"

这解决了集合的多个实例的问题,但再次 datagrid 在重做选择时遇到了一些问题,所以我添加了一个带有 datatrigger 的样式来重新应用选择

    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Style.Triggers>
                <Trigger Property="IsSelected"
                         Value="true">
                    <Setter Property="Background"
                            Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                    <Setter Property="Foreground"
                            Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>

即使重新加载页面,此触发器也会确保该行看起来被选中。

这是working sample


编辑

这里是合并 Metro.xaml 后问题的解决方案

从 ListView 的 DataGrid 中删除 DataGrid.RowStyle 并用这些替换 Metro.xaml 中提到的样式

<Style TargetType="{x:Type DataGridCell}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="FontSize" Value="16" />
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Foreground" Value="Black" />
        </Trigger>
    </Style.Triggers>
</Style>

<Style TargetType='{x:Type DataGridRow}'>
    <Setter Property="TextElement.Foreground" Value="White" />
    <Setter Property="Background" Value="Gray" />
    <Setter Property="Height" Value="50" />
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="#FFE1AF4D" />
            <Setter Property="TextElement.Foreground" Value="Black" />
        </Trigger>
    </Style.Triggers>
</Style>

【讨论】:

  • 我查看了您的样本。乍一看,它工作得很好。所以,我试图在我的真实项目中实现同样的事情。但令人惊讶的是,它在那里不起作用。所以我在示例项目中添加了 Metro.xaml 文件,它是一个包含不同元素样式的资源字典。现在您的解决方案不再起作用了。这是带有 Metro.xaml 的示例:drive.google.com/file/d/0B5WyqSALui0bVEE4QnltcWVTQlE/…
  • 感谢 pushpraj。我没有注意到你更新的答案。现在它工作正常。
  • @Vishal,我很高兴它对你有用。快乐编码:)
【解决方案2】:

它可能失去了焦点。我在部分呈现 WPF 控件的情况下看到了类似的问题。

尝试将焦点放回目标网格控件。

【讨论】:

  • 这不是问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-22
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
相关资源
最近更新 更多