2015-07-03 11 views
5

Tôi đang sử dụng MVVM và tôi muốn dữ liệu liên kết danh sách MenuViewModels với menu maim của tôi. Trong đó bao gồm một tập hợp các mục trình đơn và dấu phân cách.Làm cách nào để liên kết chính xác ViewModel (bao gồm Dấu phân tách) với Trình đơn của WPF?

Đây là mã MenuItemViewModel tôi:

public interface IMenuItemViewModel 
{ 
} 

[DebuggerDisplay("---")] 
public class SeparatorViewModel : IMenuItemViewModel 
{ 
} 

[DebuggerDisplay("{Header}, Children={Children.Count}")] 
public class MenuItemViewModel : IMenuItemViewModel, INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public MenuItemViewModel(string header, ICommand command, ImageSource imageSource) 
    { 
     Header = header; 
     Command = command; 
     ImageSource = imageSource; 

     Children = new List<IMenuItemViewModel>(); 
    } 

    public string Header { get; private set; } 
    public ICommand Command { get; private set; } 

    public ImageSource ImageSource { get; private set; } 

    public IList<IMenuItemViewModel> Children { get; private set; } 
} 

Và cửa sổ chính của tôi trông như thế này:

<Window.Resources> 
    <HierarchicalDataTemplate DataType="{x:Type ViewModel:MenuItemViewModel}" 
     ItemsSource="{Binding Children}"> 
     <MenuItem Header="{Binding Header}" 
        Command="{Binding Command}"/> 
    </HierarchicalDataTemplate> 

    <DataTemplate DataType="{x:Type ViewModel:SeparatorViewModel}"> 
     <Separator /> 
    </DataTemplate> 
</Window.Resources> 

<DockPanel> 
    <Menu DockPanel.Dock="Top" 
      ItemsSource="{Binding MenuItems}"> 
    </Menu> 
</DockPanel> 

nên được những thứ rất đơn giản. Thật không may, một trong hai mục menu có vẻ sai hoặc dấu tách là một trống menuItem (tùy thuộc vào những gì tôi đã thử).

Vì vậy, làm cách nào để có được Menu để tìm hai số DataTemplates của tôi?

Trả lời

10

Giải Quyết câu hỏi của riêng tôi

Sau khi trải qua nhiều giờ tìm kiếm trên web, tôi thấy rất nhiều ví dụ mà làm việc chống ý định tự nhiên của WPF nhưng không ai mà làm việc với nó.

Dưới đây là cách làm việc với các Menu kiểm soát và không chống lại nó ...

Một nền ít

WPF của Menu điều khiển sẽ thường tự động tạo MenuItem đối tượng cho bạn khi nó là liên kết với bộ sưu tập POCO, sử dụng thuộc tính ItemsSource.

Tuy nhiên, hành vi mặc định này có thể bị ghi đè! Sau đây là cách ...

Giải pháp

Trước tiên, bạn phải tạo một lớp dẫn xuất từ ​​ItemContainerTemplateSelector. Hoặc sử dụng lớp đơn giản tôi đã tạo:

public class MenuItemContainerTemplateSelector : ItemContainerTemplateSelector 
{ 
    public override DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl) 
    { 
     var key = new DataTemplateKey(item.GetType()); 
     return (DataTemplate) parentItemsControl.FindResource(key); 
    } 
} 

Thứ hai, bạn phải thêm một tham chiếu đến lớp MenuItemContainerTemplateSelector để đối tượng của Windows resources của bạn, như vậy:

<Window.Resources> 
    <Selectors:MenuItemContainerTemplateSelector x:Key="_menuItemContainerTemplateSelector" /> 

Thứ ba, bạn phải thiết lập hai thuộc tính (UsesItemContainerTemplateItemContainerTemplateSelector) trên cả hai MenuMenuItem (được xác định trong HierarchicalDataTemplate).

Giống như vậy:

<HierarchicalDataTemplate DataType="{x:Type ViewModel:MenuItemViewModel}" 
     ItemsSource="{Binding Children}"> 
     <MenuItem Header="{Binding Header}" 
        Command="{Binding Command}" 
        UsesItemContainerTemplate ="true" 
        ItemContainerTemplateSelector= 
        "{StaticResource _menuItemContainerTemplateSelector}"/> 
    </HierarchicalDataTemplate> 

    <Menu DockPanel.Dock="Top" 
      ItemsSource="{Binding MenuItems}" 
      UsesItemContainerTemplate="True" 
      ItemContainerTemplateSelector= 
      "{StaticResource _menuItemContainerTemplateSelector}"> 
    </Menu> 

Tại sao hoạt động

Đối với mục đích tối ưu hóa, các Menu sử dụng UsesItemContainerTemplate cờ (trong đó có một giá trị mặc định của false) để bỏ qua DataTemplate tra cứu và chỉ trở lại đối tượng MenuItem bình thường. Do đó, chúng tôi cần đặt giá trị này thành true và sau đó ItemContainerTemplateSelector hoạt động như mong đợi.

Mã hóa hạnh phúc!

1

Một giải pháp mà không có sự TemplateSelector:

cung cấp ItemContainerTemplates thay vì DataTemplates:

<ContextMenu ItemsSource="{Binding Path=MenuItems}" UsesItemContainerTemplate="True"> 
       <ContextMenu.Resources> 
       <ResourceDictionary> 
        <ItemContainerTemplate DataType="{x:Type ViewModel:MenuItemViewModel }"> 
        <MenuItem Header="{Binding Path=Header}" Command="{Binding Path=Command}" UsesItemContainerTemplate="True"> 
         <MenuItem.Icon> 
         <Image Source="{Binding Path=ImageSource}"/> 
         </MenuItem.Icon> 
        </MenuItem> 
        </ItemContainerTemplate> 
        <ItemContainerTemplate DataType="{x:Type ViewModel:SeparatorViewModel}"> 
        <Separator > 
         <Separator.Style> 
         <Style TargetType="{x:Type Separator}" BasedOn="{StaticResource ResourceKey={x:Static MenuItem.SeparatorStyleKey}}"/> 
         </Separator.Style> 
        </Separator> 
        </ItemContainerTemplate> 
       </ResourceDictionary> 
       </ContextMenu.Resources> 
      </ContextMenu> 

Ghi chú:

  • tôi đã không cố gắng cho trẻ em
  • tách styled wrong: Tôi đã phải áp dụng lại theo cách thủ công kiểu dáng
Các vấn đề liên quan