【问题标题】:How to access Quick Access tool bar command `Add to Quick Access Tool` if source binding applicable如果源绑定适用,如何访问快速访问工具栏命令“添加到快速访问工具”
【发布时间】:2015-07-22 13:12:51
【问题描述】:

如果我为它绑定了集合,我如何通过 RibbonLibrary 添加默认的快速访问项容器。当我从 UI 添加快速访问工具项时,它会抛出 在使用 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; }
}

出错


如果不清楚,请添加评论。

【问题讨论】:

    标签: c# wpf ribboncontrolslibrary


    【解决方案1】:

    问题在于 ContextMenu 正在尝试使用 ItemCollection.Add() 将项目添加到集合中,但如果使用 ItemsSource 来填充集合,则不支持此方法,并且该方法将引发异常。

    查看源码:ItemCollection.cs

    一种解决方案是隐藏 ContextMenu 以避免调用其不受支持的函数,或者尝试将其替换为您自己的自定义 ContextMenu,它绑定到 ViewModel 上的命令并更新 QuickMenuItems。

    可能存在使用附加属性的某种黑客攻击。

    【讨论】:

    • 那么还有其他替代方案或解决方案吗?
    • 还在想办法
    【解决方案2】:

    这将允许您从功能区控件和 ViewModel 添加快速菜单项。我使用了ListBox 作为 ViewModel 和RibbonQuickAccessToolBar 之间的代理。当项目被添加到ListBox 时,视图会将它们添加到RibbonQuickAccessToolBar

    创建一个折叠的ListBox,它将绑定到 ViewModel 中的集合并删除RibbonQuickAccessToolBarItemsSource 绑定:

    <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>
    

    在代码隐藏中,使用 ListBox 的 DataContextChanged 为 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; }
        }
    }
    

    【讨论】:

      【解决方案3】:

      一种解决方法是不使用 RibbonQuickAccessToolBar.ItemsSource。如果需要通知 QuickAccessToolbar 的更改,请订阅 RibbonQuickAccessToolBar.Items 的 INotifyCollectionChanged。

         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】:

        最后我可以通过代码解决我的问题,因为我正在使用 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事件。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-04
          • 2023-03-04
          • 2020-05-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多