Chúng tôi muốn đặt SelectedItem
của một ListBox
theo chương trình và muốn mục đó sau đó có tiêu điểm sao cho các phím mũi tên hoạt động liên quan đến mục đã chọn đó. Có vẻ đơn giản là đủ.Làm thế nào để bạn lập trình tập trung vào SelectedItem trong một ListBox WPF đã có tiêu điểm?
Vấn đề tuy nhiên là nếu ListBox
đã có tập trung bàn phím khi thiết SelectedItem
lập trình, trong khi nó cập nhật đúng IsSelected
tài sản trên ListBoxItem
, nó không bộ bàn phím tập trung vào nó, và do đó, các phím mũi tên di chuyển tương đối so với mục được tập trung trước đó trong danh sách và không phải mục được chọn mới như mong đợi.
Điều này rất khó hiểu đối với người dùng vì nó làm cho lựa chọn xuất hiện để nhảy xung quanh khi sử dụng bàn phím khi nó quay trở lại vị trí trước khi lựa chọn có lập trình diễn ra.
Lưu ý: Như tôi đã nói, điều này chỉ xảy ra nếu bạn lập trình đặt thuộc tính SelectedItem
trên ListBox
đã có tiêu điểm bàn phím. Nếu nó không (hoặc nếu nó không nhưng bạn để lại, sau đó quay lại ngay), khi tiêu điểm bàn phím trở về ListBox
, mục chính xác bây giờ sẽ có tiêu điểm bàn phím như mong đợi.
Dưới đây là một số mã mẫu cho thấy sự cố này. Để giới thiệu điều này, hãy chạy mã, sử dụng chuột để chọn 'Bảy' trong danh sách (do đó đặt trọng tâm vào số ListBox
), sau đó nhấp vào nút 'Kiểm tra'. Cuối cùng, chạm vào phím 'Alt' trên bàn phím của bạn để hiển thị tiêu điểm rect. Bạn sẽ thấy nó vẫn còn thực sự trên 'Bảy' và nếu bạn sử dụng mũi tên lên và xuống, chúng liên quan đến hàng đó, không phải là 'Bốn' như người dùng mong đợi.
Lưu ý rằng tôi có Focusable
được đặt thành false
trên nút không làm mất hộp danh sách tiêu điểm khi nhấn. Nếu tôi không có điều này, các ListBox
sẽ mất tập trung khi bạn nhấp vào nút, và do đó, khi tập trung quay trở lại ListBox, nó sẽ được vào đúng mục.
XAML file:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="525" Height="350" WindowStartupLocation="CenterScreen"
Title="MainWindow" x:Name="Root">
<DockPanel>
<Button Content="Test"
DockPanel.Dock="Bottom"
HorizontalAlignment="Left"
Focusable="False"
Click="Button_Click" />
<ListBox x:Name="MainListBox" />
</DockPanel>
</Window>
Mã-đằng sau:
using System.Collections.ObjectModel;
using System.Windows;
namespace Test
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainListBox.ItemsSource = new string[]{
"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"
};
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MainListBox.SelectedItem = MainListBox.Items[3];
}
}
}
Lưu ý: Một số người đã đề nghị sử dụng IsSynchronizedWithCurrentItem
, nhưng tài sản đó đồng bộ hóa các SelectedItem
của ListBox
với Current
tài sản của liên lượt xem. Nó không liên quan đến tập trung vì vấn đề này vẫn còn tồn tại.
của chúng tôi làm việc xung quanh là tạm thời đặt trọng tâm ở một nơi khác, sau đó đặt mục đã chọn, sau đó đặt trọng tâm trở lại ListBox
nhưng điều này có tác dụng undesireable người trong chúng ta phải thực hiện của chúng tôi ViewModel
nhận thức được ListBox
chính nó, sau đó thực hiện logic tùy thuộc vào việc nó có tập trung, v.v. (nghĩa là bạn không muốn chỉ đơn giản nói 'Tập trung ở nơi khác rồi quay lại đây, nếu' ở đây 'không có tiêu điểm như bạn đã đánh cắp nó từ một nơi khác.) Thêm vào đó, bạn không thể đơn giản xử lý điều này thông qua các ràng buộc khai báo. Không cần phải nói điều này là xấu.
Sau đó, một lần nữa, tàu 'xấu', do đó, có điều đó.
ContainerFromItem sẽ trả về Null nếu không có vùng chứa nào chưa được tạo cho nó, đó là trường hợp của một danh sách ảo hóa và mục đó không có màn hình. Thêm vào đó nếu bạn cố gắng thiết lập giá trị từ một ràng buộc nó bị phá vỡ khi bạn không có quyền truy cập vào ListBox, cũng không phải là bạn. (Tiếp theo bên dưới ...) – MarqueIV
Ngay cả hành vi đính kèm cũng đặt ra các vấn đề vì bạn không muốn điều khiển nhắm mắt tập trung vào ListBoxItem trừ khi a) điều khiển đã có tiêu điểm (dễ kiểm tra) và b) thay đổi đến Nếu không, bạn có thể vô tình đánh cắp lấy nét từ một điều khiển khác (trường hợp a) hoặc làm lộn xộn tiêu điểm trong điều khiển hiện tại (trường hợp b) khi ở chế độ đa lựa chọn và bỏ chọn một hàng, mà thông thường nên giữ lại tiêu điểm bàn phím, nhưng thay vào đó sẽ được đặt thành SelectedItem mới, nếu có, gây ra các hành vi kỳ lạ. – MarqueIV
Trên thực tế, suy nghĩ thứ hai, tôi nghĩ rằng tôi có công việc xung quanh cho trường hợp 'B' ở trên. Bạn tạo hành vi đính kèm như bạn đã nói, nhưng bạn không đặt nó trực tiếp trong XAML. Thay vào đó bạn tạo một thuộc tính trên ViewModel của bạn và ràng buộc hành vi đó. Bằng cách đó bạn không cần phải biết (hoặc quan tâm) ai đang lắng nghe. Sau đó, ngay trước khi bạn đặt mục đã chọn từ mã phía sau, bạn bật hành vi, chọn mục, sau đó tắt lại hành vi. Địa chỉ này 'B' ở trên. (Bạn vẫn cần 'A' tất nhiên.) Bình chọn của bạn là câu trả lời kể từ khi, mặc dù không hoàn thành, đã dẫn tôi xuống con đường này. – MarqueIV