Подтвердить что ты не робот

Как получить доступ к панели инструментов быстрого доступа "Добавить в инструмент быстрого доступа", если применяется привязка к источнику

Как добавить контейнер контейнера быстрого доступа по умолчанию в RibbonLibrary, если у меня есть привязанная коллекция для него. Его броски Операция недействительна, пока ItemSource используется, когда я добавляю элемент быстрого доступа из пользовательского интерфейса.

<r:Ribbon Name="ribbon">

        <r:Ribbon.QuickAccessToolBar>

            <r:RibbonQuickAccessToolBar ItemsSource ="{Binding QuickMenuItems, Mode=OneWay}">
                <r:RibbonQuickAccessToolBar.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <r:RibbonButton QuickAccessToolBarId="{Binding RibbonId}" Label="{Binding Label}" SmallImageSource="{Binding ImageUri}" Command="{Binding Command}"/>
                        </StackPanel>
                    </DataTemplate>
                </r:RibbonQuickAccessToolBar.ItemTemplate>
            </r:RibbonQuickAccessToolBar>

        </r:Ribbon.QuickAccessToolBar>

        <r:RibbonTab Header="Home">
            <r:RibbonGroup x:Name="Clipboard" ItemsSource ="{Binding MenuItems, Mode=OneWay}" >

                <r:RibbonGroup.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <r:RibbonButton QuickAccessToolBarId="{Binding RibbonId}" Label="{Binding Label}" SmallImageSource="{Binding ImageUri}" Command="{Binding Command}"/>
                        </StackPanel>
                    </DataTemplate>
                </r:RibbonGroup.ItemTemplate>

            </r:RibbonGroup>
        </r:RibbonTab>

    </r:Ribbon>


 ObservableCollection<RibbonItem> _MenuItems;
 ObservableCollection<RibbonItem> _QuickMenuItems;

 public ObservableCollection<RibbonItem> MenuItems
 {
      get { return _MenuItems; }
 }
 public ObservableCollection<RibbonItem> QuickMenuItems
 {
      get { return _QuickMenuItems; }
 }
public class RibbonItem
{
    public RibbonItem(string label, string imageUri, ICommand command, string ribbonId)
    {
        Label = label;
        ImageUri = imageUri;
        Command = command;
    }

    public string Label { get; private set; }

    public string ImageUri { get; private set; }

    public ICommand Command { get; private set; }

    public string RibbonId { get; private set; }
}

Ошибка при

введите описание изображения здесь

введите описание изображения здесь
Добавить комментарий, если не ясно.

4b9b3361

Ответ 1

Это позволит вам добавлять быстрые элементы меню из ленточного элемента управления и ViewModel. Я использовал ListBox как прокси-сервер между ViewModel и RibbonQuickAccessToolBar. Когда элементы добавляются в ListBox, представление добавит их в RibbonQuickAccessToolBar.

Создайте свернутый ListBox, который будет привязан к коллекции в ViewModel и удалит привязку ItemsSource для RibbonQuickAccessToolBar:

<ListBox ItemsSource="{Binding QuickMenuItems, Mode=OneWay}"
            x:Name="ProxyListBox"
            Visibility="Collapsed"/>
<ribbon:Ribbon Name="ribbon">
    <ribbon:Ribbon.QuickAccessToolBar>
        <ribbon:RibbonQuickAccessToolBar x:Name="QuickAccessToolBar" DataContextChanged="QuickAccessToolBar_OnDataContextChanged">
            <ribbon:RibbonQuickAccessToolBar.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <ribbon:RibbonButton QuickAccessToolBarId="{Binding RibbonId}" Label="{Binding Label}" SmallImageSource="{Binding ImageUri}" Command="{Binding Command}"/>
                    </StackPanel>
                </DataTemplate>
            </ribbon:RibbonQuickAccessToolBar.ItemTemplate>
        </ribbon:RibbonQuickAccessToolBar>
    </ribbon:Ribbon.QuickAccessToolBar>
    <ribbon:RibbonTab Header="Home">
        <ribbon:RibbonGroup x:Name="Clipboard" ItemsSource ="{Binding MenuItems, Mode=OneWay}" >
            <ribbon:RibbonGroup.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <ribbon:RibbonButton QuickAccessToolBarId="{Binding RibbonId}" Label="{Binding Label}" SmallImageSource="{Binding ImageUri}" Command="{Binding Command}"/>
                    </StackPanel>
                </DataTemplate>
            </ribbon:RibbonGroup.ItemTemplate>
        </ribbon:RibbonGroup>
    </ribbon:RibbonTab>
</ribbon:Ribbon>

В коде используется DataContextChanged из ListBox для присоединения обработчика событий для события ListBox.ItemsSource CollectionChanged:

private void ProxyListBox_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach (var newItem in e.NewItems)
        {
            QuickAccessToolBar.Items.Add(newItem);
        }
    }

    if (e.OldItems != null)
    {
        foreach (var oldItem in e.OldItems)
        {
            QuickAccessToolBar.Items.Remove(oldItem);
        }
    }
}

private void QuickAccessToolBar_OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    ((INotifyCollectionChanged)ProxyListBox.Items).CollectionChanged += ProxyListBox_CollectionChanged;
}

ViewModel такой же, как и раньше:

class RibbonViewModel
{
    ObservableCollection<RibbonItem> _MenuItems;

    ObservableCollection<RibbonItem> _QuickMenuItems;

    public ObservableCollection<RibbonItem> MenuItems
    {
        get { return _MenuItems; }
    }

    public ObservableCollection<RibbonItem> QuickMenuItems
    {
        get { return _QuickMenuItems; }
    }

    public RibbonViewModel()
    {
        _QuickMenuItems = new ObservableCollection<RibbonItem>();
        _MenuItems = new ObservableCollection<RibbonItem>();
    }

    public class RibbonItem
    {
        public RibbonItem(string label, string imageUri, ICommand command)
        {
            Label = label;
            ImageUri = imageUri;
            Command = command;
        }

        public string Label { get; private set; }

        public string ImageUri { get; private set; }

        public ICommand Command { get; private set; }

        public string RibbonId { get; private set; }
    }
}

Ответ 2

Проблема заключается в том, что ContextMenu пытается добавить элементы в коллекцию с помощью ItemCollection.Add(), но этот метод не поддерживается, если вместо этого элемент ItemsSource используется для заполнения коллекции, а метод генерирует исключение.

Смотрите исходный код: ItemCollection.cs

Одним из решений было бы скрыть ContextMenu, чтобы избежать вызова его неподдерживаемых функций или попытаться заменить его собственным пользовательским ContextMenu, который привязывается к команде в ViewModel и обновляет QuickMenuItems.

Может быть какой-то взлом с использованием прикрепленных свойств.

Ответ 3

Обходным решением было бы не использовать RibbonQuickAccessToolBar.ItemsSource. Если вам необходимо уведомить об изменениях в QuickAccessToolbar, подпишитесь на INotifyCollectionChanged of RibbonQuickAccessToolBar.Items.

   public RibbonWindow() {
        InitializeComponent();
        ((INotifyCollectionChanged)QuickAccessToolBar.Items).CollectionChanged += QuickAccessToolBar_ItemsCollectionChanged;
    }

    private void QuickAccessToolBar_ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
        switch (e.Action) {
           //Do stuff or synchronize to observableCollection
        }
    }

Ответ 4

Наконец, я могу решить свою проблему по коду за тем, что я использую Attach Behavior для RibbonWindow, вот решение:

public class RibbonWindowQuickAccessItemBehaviour : Behavior<RibbonWindow>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.Loaded += RibbonControl_Loaded;
        AssociatedObject.Closing += RibbonControl_Closing;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.Loaded -= RibbonControl_Loaded;
        AssociatedObject.Closing -= RibbonControl_Closing;
    }

    private void RibbonControl_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        var ribbonWindow = (RibbonWindow)sender;

        var ribbon = ribbonWindow.FindAllChildrenOfType<Microsoft.Windows.Controls.Ribbon.Ribbon>().Where(a => a.Name == "ribbon").FirstOrDefault();

        if (ribbon == null) return;

        var dataContext = ribbon.DataContext;

        if (dataContext is IRibbonMainWindowViewModel)
        {
            IRibbon windowsRibbon = (dataContext as IRibbonMainWindowViewModel).WindowRibbon;

            windowsRibbon.QuickAccessMenuItems.Clear();

            if (ribbon.QuickAccessToolBar != null && ribbon.QuickAccessToolBar.Items != null && ribbon.QuickAccessToolBar.Items.Count > 0)
            {
                foreach (var item in ribbon.QuickAccessToolBar.Items)
                {
                    if (item is RibbonButton)
                    {
                        var ribbonItem = item as RibbonButton;

                        windowsRibbon.QuickAccessMenuItems.Add
                            (new Gno.Framework.ClientShell.Ribbon.MenuItem(ribbonItem.Label,
                                ribbonItem.SmallImageSource == null ? string.Empty : ribbonItem.SmallImageSource.ToString(),
                                ribbonItem.Command));
                    }
                }
            }
        }
    }

    private void RibbonControl_Loaded(object sender, RoutedEventArgs e)
    {
        var ribbonWindow = (RibbonWindow)sender;

        var ribbon = ribbonWindow.FindAllChildrenOfType<Microsoft.Windows.Controls.Ribbon.Ribbon>().Where(a => a.Name == "ribbon").FirstOrDefault();

        if (ribbon == null) return;

        var dataContext = ribbon.DataContext;

        if (dataContext is IRibbonMainWindowViewModel)
        {
            IRibbon windowsRibbon = (dataContext as IRibbonMainWindowViewModel).WindowRibbon;

            var quickAccessMenus = windowsRibbon.QuickAccessMenuItems;

            if (quickAccessMenus != null && quickAccessMenus.Count > 0)
            {
                ribbon.QuickAccessToolBar = new RibbonQuickAccessToolBar();

                foreach (var quickMenu in windowsRibbon.QuickAccessMenuItems)
                {
                    var ribbonButton = new RibbonButton();

                    ribbonButton.Command = quickMenu.Command;
                    ribbonButton.Label = quickMenu.Header;

                    if (!string.IsNullOrEmpty(quickMenu.ImageUri))
                        ribbonButton.SmallImageSource = new BitmapImage(new Uri(quickMenu.ImageUri));

                    ribbon.QuickAccessToolBar.Items.Add(ribbonButton);
                }
            }
        }
    }
}

На самом деле это код для сохранения QuickAccessToolBarItem, поэтому необходимо связать событие Window Close и Load.