2012-10-06 29 views
7

Tôi đang sử dụng MVVM và hiển thị hai hộp danh sách trên một cửa sổ. Tôi ràng buộc từ cả hai hộp danh sách đó cùng một lúc với các trường khác nhau gọi chúng là A và B. A và B sau đó là cả hai sửa đổi C. Để thực hiện công việc này, tôi muốn chỉ có một mục từ hai hộp danh sách được chọn cùng một lúc, sao cho A không ghi đè C khi B được chọn. Làm thế nào tôi có thể hạn chế điều này?Nhiều Hộp danh sách WPF chỉ với một mục được chọn tại một thời điểm

Cảm ơn!

+1

Bạn muốn lựa chọn được xóa trong một ListBox khi lựa chọn được thực hiện trong ListBox khác? Tôi thấy câu hỏi của bạn khó hiểu. – Simon

+0

Tôi về cơ bản muốn biết làm thế nào tôi có thể ràng buộc một cái gì đó giống như một IsFocused/IsSelected Listbox bất động sản để một bool trong mô hình xem của tôi. – user1722960

+2

Bạn có thể liên kết SelectedIndex của một ListBox với một thuộc tính trong mô hình khung nhìn của bạn. Vì vậy, ví dụ khi SelectedIndexA của ListBoxA được thiết lập, bạn có thể đặt SelectedIndexB của ListBoxB thành -1 để xóa (các) lựa chọn của ListBoxB và ngược lại. Đó có phải là ý định của bạn không? – Simon

Trả lời

8

Tôi có thể nghĩ ra một vài cách để thực hiện việc này.

Một cách là bạn có thể liên kết ListBox.SelectedIndex trong 2 Hộp danh sách của mình để thay đổi thông báo các thuộc tính ViewModel.

Ví dụ trong View của bạn:

<ListBox SelectedIndex="{Binding SelectedIndexA}"> 
    <ListBoxItem Content="Item 1"/> 
    <ListBoxItem Content="Item 2"/> 
</ListBox> 
<ListBox SelectedIndex="{Binding SelectedIndexB}"> 
    <ListBoxItem Content="Item 1"/> 
    <ListBoxItem Content="Item 2"/> 
</ListBox> 

Và trong ViewModel của bạn:

public int SelectedIndexA 
{ 
    get { return _selectedIndexA; } 
    set 
    { 
     _selectedIndexA = value; 
     _selectedIndexB = -1; 
     OnPropertyChanged("SelectedIndexB"); 
    } 
} 

public int SelectedIndexB 
{ 
    get { return _selectedIndexB; } 
    set 
    { 
     _selectedIndexB = value; 
     _selectedIndexA = -1; 
     OnPropertyChanged("SelectedIndexA"); 
    } 
} 

Một cách khác sẽ có một tài sản gắn liền như 'GroupName', nơi bạn có thể Selectors nhóm (ListBox thừa hưởng từ Selector) để đảm bảo chỉ một Selector trong nhóm có một mục được chọn cùng một lúc.

Ví dụ:

public static class SingleSelectionGroup 
{ 
    public static readonly DependencyProperty GroupNameProperty = 
     DependencyProperty.RegisterAttached("GroupName", typeof(string), typeof(SingleSelectionGroup), 
              new UIPropertyMetadata(OnGroupNameChanged)); 

    public static string GetGroupname(Selector selector) 
    { 
     return (string) selector.GetValue(GroupNameProperty); 
    } 

    public static void SetGroupName(Selector selector, string value) 
    { 
     selector.SetValue(GroupNameProperty, value); 
    } 

    private static void OnGroupNameChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     var selector = (Selector) dependencyObject; 

     if (e.OldValue != null) 
      selector.SelectionChanged -= SelectorOnSelectionChanged; 
     if (e.NewValue != null) 
      selector.SelectionChanged += SelectorOnSelectionChanged; 
    } 

    private static void SelectorOnSelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     if (e.AddedItems.Count == 0) 
      return; 

     var selector = (Selector) sender; 
     var groupName = (string) selector.GetValue(GroupNameProperty); 
     var groupSelectors = GetGroupSelectors(selector, groupName); 

     foreach (var groupSelector in groupSelectors.Where(gs => !gs.Equals(sender))) 
     { 
      groupSelector.SelectedIndex = -1; 
     } 
    } 

    private static IEnumerable<Selector> GetGroupSelectors(DependencyObject selector, string groupName) 
    { 
     var selectors = new Collection<Selector>(); 
     var parent = GetParent(selector); 
     GetGroupSelectors(parent, selectors, groupName); 
     return selectors; 
    } 

    private static DependencyObject GetParent(DependencyObject depObj) 
    { 
     var parent = VisualTreeHelper.GetParent(depObj); 
     return parent == null ? depObj : GetParent(parent); 
    } 

    private static void GetGroupSelectors(DependencyObject parent, Collection<Selector> selectors, string groupName) 
    { 
     var childrenCount = VisualTreeHelper.GetChildrenCount(parent); 
     for (int i = 0; i < childrenCount; i++) 
     { 
      var child = VisualTreeHelper.GetChild(parent, i); 
      var selector = child as Selector; 
      if (selector != null && (string) selector.GetValue(GroupNameProperty) == groupName) 
       selectors.Add(selector); 

      GetGroupSelectors(child, selectors, groupName); 
     } 
    } 
} 

Và trong View của bạn:

<ListBox my:SingleSelectionGroup.GroupName="Group A"> 
    <ListBoxItem Content="Item 1 (Group A)"/> 
    <ListBoxItem Content="Item 2 (Group A)"/> 
</ListBox> 
<ListBox my:SingleSelectionGroup.GroupName="Group A"> 
    <ListBoxItem Content="Item 1 (Group A)"/> 
    <ListBoxItem Content="Item 2 (Group A)"/> 
</ListBox> 

<ListBox my:SingleSelectionGroup.GroupName="Group B"> 
    <ListBoxItem Content="Item 1 (Group B)"/> 
    <ListBoxItem Content="Item 2 (Group B)"/> 
</ListBox> 
<ListBox my:SingleSelectionGroup.GroupName="Group B"> 
    <ListBoxItem Content="Item 1 (Group B)"/> 
    <ListBoxItem Content="Item 2 (Group B)"/> 
</ListBox> 

Nếu bạn phải bấm vào một mục hai lần trước khi nó được đánh dấu, bạn có thể sử dụng một cách giải quyết nhanh chóng như thế này:

<Style TargetType="ListBoxItem"> 
    <Style.Triggers> 
     <EventTrigger RoutedEvent="GotKeyboardFocus"> 
      <BeginStoryboard> 
       <Storyboard> 
        <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(ListBoxItem.IsSelected)"> 
         <DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True" /> 
        </BooleanAnimationUsingKeyFrames> 
       </Storyboard> 
      </BeginStoryboard> 
     </EventTrigger> 
    </Style.Triggers> 
</Style> 
+0

câu trả lời tuyệt vời !!! Tôi đã thực hiện một số sửa chữa nhìn vào câu trả lời dưới đây. Tôi vẫn còn một vấn đề nhỏ. Nếu bạn có thể cố gắng giải quyết nó thì nó sẽ rất tốt đẹp cho bạn. Nếu bạn trở nên tự do thì hãy xem xét vấn đề của tôi ở đây: http://stackoverflow.com/questions/22209877/movefocus-from-one-listbox-to-another – Vishal

6

Nếu có ai đã sử dụng ListBox/ListView bên trong ItemsControl và có sự cố sau sau khi sử dụng câu trả lời ở trên:

  1. Khi bạn nhấp vào bất kỳ Mục nào trong danh sách1 mục được chọn.
  2. Khi bạn bấm vào bất kỳ mục nào trong hộp danh sách2 mục đã chọn của listbox1 không được chọn nhưng không có mục nào trong hộp danh sách2 được chọn.
  3. Khi bạn bấm lại vào bất kỳ mục nào trong hộp danh sách2 mục được chọn.

Chỉ cần thêm dưới đây XAML để phong cách của ListBoxItem của bạn:

<Style TargetType="ListBoxItem"> 
    <Style.Triggers> 
     <Trigger Property="IsKeyboardFocusWithin" Value="True"> 
      <Setter Property="IsSelected" Value="True"></Setter> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

Ngoài ra, Nếu ai là nhận được lỗi sau sau khi sử dụng mã trong câu trả lời ở trên:

GroupName is already registered by Selector 

Hãy thay đổi số third parameter typeof(......) trong khai báo thuộc tính phụ thuộc thành Tên của lớp học.

+0

Đó là một sự theo dõi tuyệt vời. Cảm ơn bạn! – usefulBee

+0

@usefulBee Bạn được chào đón. – Vishal

+0

Cảm ơn bạn đã xem xét điều đó. Tôi đã không thực sự cần tài sản đính kèm cho đến ngày hôm nay để phát hiện vấn đề với các mục được chọn không được đánh dấu. Như một sửa chữa nhanh chóng, tôi đã sử dụng EventTrigger thay vì ở trên vì các trình kích hoạt thông thường được đặt lại khi giá trị là sai, nghĩa là lựa chọn sẽ bị xóa khi mục mất tiêu điểm bàn phím. Điều này là không mong muốn trong tình huống của tôi. – Simon

Các vấn đề liên quan