Comments (18)
We have created our own FluentRibbonRegionAdapter for PRISM and use this way to enable the MVVM way of things.
from fluent.ribbon.
I've got a solution to this problem to be used in PrismLib, hopefully, it's valid.
In Prism, instead of Behavior
we can use Adapter
, just like @dymanoid mentioned.
So we can have an adapter for the Ribbon
itself so that we can add single RibbonTabItem
s to it and we can have an adapter for RibbonTabItem
so that we can add RibbonGroupBox
s to it, which enables even more granularity.
public class RibbonRegionAdapter : RegionAdapterBase<Fluent.Ribbon>
{
public RibbonRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
: base(regionBehaviorFactory)
{
}
protected override void Adapt(IRegion region, Fluent.Ribbon regionTarget)
{
// If control has child items, move them to the region
if(regionTarget.Tabs.Count > 0)
{
foreach(object childItem in regionTarget.Tabs)
region.Add(childItem);
}
// hookup for future changes
region.Views.CollectionChanged += (sender, e) =>
{
switch(e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
foreach(Fluent.RibbonTabItem item in e.NewItems)
regionTarget.Tabs.Add(item);
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
foreach(Fluent.RibbonTabItem item in e.OldItems)
regionTarget.Tabs.Remove(item);
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
{
var views = sender as IViewsCollection;
regionTarget.Tabs.Clear();
foreach(Fluent.RibbonTabItem item in views)
regionTarget.Tabs.Add(item);
if(regionTarget.Tabs.Count > 0)
regionTarget.SelectedTabIndex = 0; // force select first already
break;
}
}
};
}
protected override IRegion CreateRegion()
{
return new SingleActiveRegion();
}
}
public class RibbonTabRegionAdapter : RegionAdapterBase<Fluent.RibbonTabItem>
{
public RibbonTabRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
: base(regionBehaviorFactory)
{
}
protected override void Adapt(IRegion region, Fluent.RibbonTabItem regionTarget)
{
// If control has child items, move them to the region
if(regionTarget.Groups.Count > 0)
{
foreach(object childItem in regionTarget.Groups)
region.Add(childItem);
}
// hookup for future changes
region.Views.CollectionChanged += (sender, e) =>
{
switch(e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
foreach(Fluent.RibbonGroupBox item in e.NewItems)
regionTarget.Groups.Add(item);
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
foreach(Fluent.RibbonGroupBox item in e.OldItems)
regionTarget.Groups.Remove(item);
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
{
var views = sender as IViewsCollection;
regionTarget.Groups.Clear();
foreach(Fluent.RibbonGroupBox item in views)
regionTarget.Groups.Add(item);
break;
}
}
};
}
protected override IRegion CreateRegion()
{
return new AllActiveRegion();
}
}
Then you need to register them in your bootstrapper:
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
var mappings = base.ConfigureRegionAdapterMappings();
if(mappings == null) return null;
mappings.RegisterMapping(typeof(Fluent.Ribbon),
Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<RibbonRegionAdapter>());
mappings.RegisterMapping(typeof(Fluent.RibbonTabItem),
Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<RibbonTabRegionAdapter>());
return mappings;
}
And then you just use this region as normal: so you create a Fluent:Ribbon
element in XAML that has specified prism:RegionManager.RegionName
and then you can use regular view registration within this region:
_regionManager.RegisterViewWithRegion(<name of the region>, typeof(<type of the Fluent:RibbonTabItem XAML control>));
(the same applies to registering Fluent:RibbonGroupBox
XAML within Fluent:RibbonTabItem
element)
You can also use ViewSortHint
attribute on your ribbon views to have them sorted properly. That's because prism at some point calls NotifyCollectionChangedAction.Reset
and views in IViewsCollection
are sorted by this attribute (to be honest, the sorting should also be taken into account for NotifyCollectionChangedAction.Add
action, but that will complicate things a little).
I briefly tested it and it looks ok. Hope this helps someone.
from fluent.ribbon.
I solved this issue with a behaviour, see below
<fluent:Ribbon x:Name="Menu"
Grid.Row="0"
AutomaticStateManagement="False"
IsQuickAccessToolBarVisible="False">
<i:Interaction.Behaviors>
<behaviors:FluentRibbonTabBindingBehaviour Tabs="{Binding NavigationService.RibbonMenu}" />
</i:Interaction.Behaviors>
</fluent:Ribbon>
public class FluentRibbonTabBindingBehaviour : Behavior
{
public static readonly DependencyProperty TabsProperty =
DependencyProperty.Register("Tabs", typeof(List),
typeof(FluentRibbonTabBindingBehaviour),
new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = true });
public List<RibbonTabItem> Tabs
{
get { return (List<RibbonTabItem>)GetValue(TabsProperty); }
set { SetValue(TabsProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += OnLoaded;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Loaded -= OnLoaded;
}
void OnLoaded(object sender, RoutedEventArgs e)
{
if (Tabs != null && Tabs.Any())
{
AssociatedObject.Tabs.Clear();
foreach (var tab in Tabs)
{
AssociatedObject.Tabs.Add(tab);
}
}
}
}
from fluent.ribbon.
Also reported here: https://fluent.codeplex.com/workitem/22327
from fluent.ribbon.
I've just done a MVVM design with Microsoft's Ribbon and its near perfect with the use of DataTemplates and Styles. You pretty much bind up all the "collection" controls with ease. Just a shame its near impossible to re-style and re-template the dam thing and there is no backstage.
Fixing Fluent Ribbon so its more inline with System.Windows.Controls.Ribbon (Bindable and supports MVVM) would probably need a breaking change; especially with regard to the templates. Pretty much needs Ribbon to derive from Selector and the need to distinguish between the Item and the Item Container.
v4?
from fluent.ribbon.
As i already mentioned on codeplex, i got no plans to improve MVVM support myself.
I only use the ribbon at work and we built a factory which builds the bridge from MVVM to the ribbon for us. Sadly i am not allowed to share the code and my employer wouldn't be happy if i'd invest time improving MVVM support when we don't need it.
But as also mentioned before, if anyone has time to improve MVVM support i would be happy to accept pull requests. ;-)
from fluent.ribbon.
Nice to see that you found a solution but we have to support it native and not by adding our own way of databinding.
from fluent.ribbon.
The way I handle this is by using the Prism event aggregator with my Prism modules. When a module loads in the application, the module checks if the user has permission to a certain menu item, and if they do it publishes a message which is subscribed in the main window code behind, and the code behind has the logic to build the ribbon.
from fluent.ribbon.
@dymanoid can you please share your solution?
thanks :)
from fluent.ribbon.
@dymanoid can you please share your solution?
from fluent.ribbon.
Inspired by @philc71 's solution, I've manage to write another variant of behavior which uses CollectionChanged
event of the observable collection to observe the ribbon tab items in the ViewModel. The general idea is that we subscribe to the CollectionChanged
of the observable collection. Whenever items in the observable collection has changed, we will update the ribbon items accordingly. As mentioned by @batzen , this is not a native solution for the Ribbon.
Note that NotifyCollectionChangedAction.Replace
and NotifyCollectionChangedAction.Reset
is not implemented.
Here is the codes for the behavior:
public class RibbonBehaviour : Behavior<Ribbon>
{
private static NotifyCollectionChangedEventHandler CollectionChangedEventHandler;
private static void OnTabsChangeCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = d as RibbonBehaviour;
var ribbon = behavior.AssociatedObject as Ribbon;
var oldItems = e.OldValue as ObservableCollection<IRibbonTabItem>;
var newItems = e.NewValue as ObservableCollection<IRibbonTabItem>;
if (oldItems != null)
{
oldItems.CollectionChanged -= CollectionChangedEventHandler;
}
ribbon.Tabs.Clear();
if (newItems != null)
{
newItems.CollectionChanged += CollectionChangedEventHandler;
foreach (var item in newItems)
{
ribbon.Tabs.Add(item.View);
}
}
}
private static void OnTabsCollectionChanged(Ribbon ribbon, NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (IRibbonTabItem item in args.NewItems)
{
ribbon.Tabs.Add(item.View);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (IRibbonTabItem item in args.OldItems)
{
ribbon.Tabs.Remove(item.View);
}
break;
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
throw new NotImplementedException(string.Format("'{0}' action is not supported, yet", args.Action));
}
}
public static readonly DependencyProperty TabItemsSourceProperty =
DependencyProperty.Register("TabItemsSource", typeof(ObservableCollection<IRibbonTabItem>), typeof(RibbonBehaviour), new FrameworkPropertyMetadata(null, OnTabsChangeCallback) { BindsTwoWayByDefault = true });
public ObservableCollection<IRibbonTabItem> TabItemsSource
{
get
{
return (ObservableCollection<IRibbonTabItem>)GetValue(TabItemsSourceProperty);
}
set
{
SetValue(TabItemsSourceProperty, value);
}
}
protected override void OnAttached()
{
base.OnAttached();
CollectionChangedEventHandler = (s, e) => OnTabsCollectionChanged(AssociatedObject, e);
}
protected override void OnDetaching()
{
base.OnDetaching();
CollectionChangedEventHandler = null;
}
}
Full solution (VS 2017) can be found here: BindableTabsDemo.zip
from fluent.ribbon.
@MeirionHughes Could you please give me an simple example or a template project about how you do MVVM design with Microsoft's Ribbon?I've just compare the fluent and the Microsoft's ribbon, but I cannot find a good way to implement mvvm by use them. This is my email:[email protected]. Thanks a lot!
from fluent.ribbon.
@violet701 may i ask why you prefer Microsoft's?
from fluent.ribbon.
@batzen sorry about my last comment. i am not mean that, but just what to know which one can use mvvm smoothly. i haven't decided which one to use in my project now
from fluent.ribbon.
@violet701 you don't have to be sorry. I'm just curious. MVVM support in the Microsoft Ribbon is definitely better than in Fluent.Ribbon but i had many deadlock issues during binding operations when i last used it. The custom window chrome from Microsoft will also cause you some headache i guess. And even Microsoft recently chose Fluent.Ribbon over their own Ribbon in the newer version of WinDBG. ;-)
from fluent.ribbon.
@ZmorzynskiK, does your adapter handle contextual tabs as well?
from fluent.ribbon.
@znakeeye I don't know to be honest, you will have to try it.
from fluent.ribbon.
Closing because no one seems interested in helping with this.
from fluent.ribbon.
Related Issues (20)
- RibbonComboBox cannot be customized based on the original RibbonComboBox style
- Padding and BorderBrush of the gallery control do not work
- MenuItems, having a submenu, do not stay highlighted when MenuItem from the submenu is highlighted HOT 1
- LauncherIcon not rendered correctly and items in QAT can be removed from QAT in it's popup HOT 1
- Button Icon HOT 3
- Text not disapearing HOT 2
- StartScreen is opening the first time only HOT 1
- Popup of DropDownButton/SplitButton has unwanted MinHeight HOT 4
- fluent.ribbon is missing NuGet package README file
- wpf calendar size issu in dropdown button HOT 2
- Port for Avalonia HOT 1
- Fluent 11 Quick Access panel HOT 1
- GroupName causes the selected ToggleButton to no longer trigger the click event HOT 2
- Using the Fluent.Ribbon with Prism HOT 1
- Fluent:Button Size Middle not working anymore HOT 2
- How to Prevent ContextMenu from Displaying Alongside the System Context Menu When Right-Clicking the Window Title Bar Multiple Times HOT 3
- Do RibbonContextualTabGroups support scrolling? HOT 3
- DropDownButton Size="Middle" does not obey the sizing. HOT 2
- Dropdown list in SplitButton HOT 1
- Cannot find source for binding: BindingExpression:Path=TitleBar.ActualHeight in Page HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fluent.ribbon.