Nano Hash - криптовалюты, майнинг, программирование

Как включить связанный с данными список элементов меню в другой элемент меню в WPF?

У меня есть «Файл» MenuItem, где я хотел бы отобразить список недавно открытых файлов.

Вот xaml, который у меня есть сейчас:

<MenuItem Header="File}">
  <MenuItem Header="Preferences..." Command="{Binding ShowOptionsViewCommand}" />
  <Separator />
  <ItemsControl ItemsSource="{Binding RecentFiles}">
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <MenuItem Header="{Binding DisplayPath}" CommandParameter="{Binding}"
            Command="{Binding Path=DataContext.OpenRecentFileCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">
        </MenuItem>
      </DataTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
  <Separator />
  <MenuItem Header="Exit" Command="{Binding CloseCommand}" />
</MenuItem>

Однако, когда я использую этот код, вокруг MenuItem появляется странное смещение, и кажется, что вокруг них есть контейнер. Как я могу избавиться от этого?

Вот скриншот того, как это выглядит:

http://www.cote-soleil.be/FileMenu.png

09.09.2009


Ответы:


1

«Странное смещение» — это MenuItem. Родитель MenuItem уже создает для вас дочерний элемент MenuItem, но ваш DataTemplate добавляет второго. Попробуй это:

<MenuItem Header="File}">
  <MenuItem Header="Preferences..." Command="{Binding ShowOptionsViewCommand}" />
  <Separator />
  <ItemsControl ItemsSource="{Binding RecentFiles}">
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <TextBlock Text="{Binding DisplayPath}"/>
      </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
      <Style TargetType="MenuItem">
        <Setter Property="Command" Value="{Binding DataContext.OpenRecentFileCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
        <Setter Property="CommandParameter" Value="{Binding}"/>
      </Style>
    </ItemsControl.ItemContainerStyle>
  </ItemsControl>
  <Separator />
  <MenuItem Header="Exit" Command="{Binding CloseCommand}" />
</MenuItem>

Обратите внимание на упрощенный DataTemplate, который содержит только TextBlock, и ItemContainerStyle для установки свойств сгенерированного MenuItem.

09.09.2009
  • Это выглядит многообещающе, но я получаю исключение, указывающее, что стиль, предназначенный для типа «MenuItem», не может быть применен к типу «ContentPresenter». У вас есть идея, как это исправить? 09.09.2009
  • Не правильно прочитал ваш код. Вы не можете смешивать сгенерированные элементы с несгенерированными. Избавьтесь от ItemsControl и вместо этого привяжите MenuItem верхнего уровня. Просто вставьте несгенерированные элементы, такие как Preferences, в коллекцию элементов меню или используйте CompositeCollection, чтобы разделить их. 09.09.2009
  • Я пытался использовать CompositeCollection, но не могу привязать CollectionContainer к своей виртуальной машине из-за ошибки в wpf. Я не хочу помещать другой элемент MenuItem в список, потому что он там не принадлежит. Итак, в конце концов, я просто создал подменю «Последние файлы» (у меня это уже получилось, но я действительно хотел, чтобы список был в меню «Файл»). 10.09.2009

  • 2

    Я попытался использовать CompositeCollection, как предложил Кент Бугаарт, но не смог заставить его работать из-за ошибка в wpf, не позволяющая использовать привязку RelativeSource в файле CollectionContainer.

    Решение, которое я использовал, состоит в том, чтобы RecentFiles в собственном подменю было привязано к коллекции через свойство ItemsSource.

    Я действительно хотел иметь список в меню «Файл», но я думаю, что это следующая лучшая вещь...

    Изменить

    Вдохновленный этой статьей, я создал собственный и более общий MenuItemList:

    public class MenuItemList : Separator {
    
      #region Private Members
    
      private MenuItem m_Parent;
      private List<MenuItem> m_InsertedMenuItems;
    
      #endregion
    
      public MenuItemList() {
        Loaded += (s, e) => HookFileMenu();
      }
    
      private void HookFileMenu() {
        m_Parent = Parent as MenuItem;
        if (m_Parent == null) {
          throw new InvalidOperationException("Parent must be a MenuItem");
        }
        if (ParentMenuItem == m_Parent) {
          return;
        }
        if (ParentMenuItem != null) {
          ParentMenuItem.SubmenuOpened -= _FileMenu_SubmenuOpened;
        }
        ParentMenuItem = m_Parent;
        ParentMenuItem.SubmenuOpened += _FileMenu_SubmenuOpened;
      }
    
      private void _FileMenu_SubmenuOpened(object sender, RoutedEventArgs e) {
        DataBind();
      }
    
      #region Properties
    
      public MenuItem ParentMenuItem { get; private set; }
    
      #region ItemsSource
    
      /// <summary>
      /// ItemsSource Dependency Property
      /// </summary>
      public static readonly DependencyProperty ItemsSourceProperty =
          DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(MenuItemList),
              new FrameworkPropertyMetadata(null,
                  new PropertyChangedCallback(OnItemsSourceChanged)));
    
      /// <summary>
      /// Gets or sets a collection used to generate the content of the <see cref="MenuItemList"/>. This is a dependency property.
      /// </summary>
      public IEnumerable ItemsSource {
        get { return (IEnumerable) GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
      }
    
      /// <summary>
      /// Handles changes to the ItemsSource property.
      /// </summary>
      private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        ((MenuItemList) d).OnItemsSourceChanged(e);
      }
    
      /// <summary>
      /// Provides derived classes an opportunity to handle changes to the ItemsSource property.
      /// </summary>
      protected virtual void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e) {
        DataBind();
      }
    
      #endregion
    
      #region ItemContainerStyle
    
      /// <summary>
      /// ItemsContainerStyle Dependency Property
      /// </summary>
      public static readonly DependencyProperty ItemContainerStyleProperty =
          DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(MenuItemList),
              new FrameworkPropertyMetadata((Style) null));
    
      /// <summary>
      /// Gets or sets the <see cref="System.Windows.Style"/> that is applied to the container element generated for each item. This is a dependency property.
      /// </summary>
      public Style ItemContainerStyle {
        get { return (Style) GetValue(ItemContainerStyleProperty); }
        set { SetValue(ItemContainerStyleProperty, value); }
      }
    
      #endregion
    
      #endregion
    
      private void DataBind() {
        RemoveMenuItems();
        InsertMenuItems();
      }
    
      private void RemoveMenuItems() {
        if (m_InsertedMenuItems != null) {
          foreach (var menuItem in m_InsertedMenuItems) {
            ParentMenuItem.Items.Remove(menuItem);
          }
        }
      }
    
      private void InsertMenuItems() {
        if (ItemsSource == null) {
          return;
        }
        if (ParentMenuItem != null) {
          m_InsertedMenuItems = new List<MenuItem>();
          int iMenuItem = ParentMenuItem.Items.IndexOf(this);
          foreach (var item in ItemsSource) {
            var menuItem = new MenuItem();
            menuItem.DataContext = item;
            menuItem.Style = ItemContainerStyle;
            ParentMenuItem.Items.Insert(++iMenuItem, menuItem);
            m_InsertedMenuItems.Add(menuItem);
          }
        }
      }
    
    }
    

    Это далеко не идеально, но это работает для меня. Не стесняйтесь комментировать это...

    09.09.2009

    3

    Вместо этого попробуйте использовать HierarchicalDataTemplate с внутренним ContentPresenter. Посмотрите на этот ответ SO для более подробной информации.

    09.09.2009
  • Ответ SO, который вы связали, действительно для подменю. Я бы хотел, чтобы динамический список был частью нединамического меню... У вас есть другие идеи? 09.09.2009
  • Итак, вы хотите объединить некоторые динамические элементы меню в статически определенное меню? Насколько я знаю, когда вы выполняете привязку данных, вы либо привязываете полный ItemsSource, либо создаете содержимое вручную (либо в XAML, либо из кода). Что бы я сделал, так это привязать данные всего меню к MenuItemViewModel, но затем убедиться, что через API можно редактировать только динамический список. 09.09.2009

  • 4

    Ошибка, о которой говорилось выше, исправлена. Обратите внимание, что я смешал список последних файлов с командой закрытия. Список последних файлов находится в отдельном меню. Это работает:

    <MenuItem Header="Recent Files" ItemsSource="{Binding RecentFiles}">
    <MenuItem.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding DisplayPath}" ToolTip="{Binding FullPath}" />
        </DataTemplate>
    </MenuItem.ItemTemplate>
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Command" Value="{Binding DataContext.SelectRecentFileCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
            <Setter Property="CommandParameter" Value="{Binding}"/>
            <Setter Property="IsChecked" Value="{Binding IsChecked}" />
        </Style>
    </MenuItem.ItemContainerStyle>
    </MenuItem>
    
    19.10.2018
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..