Splitwirez / AvaloniaRibbon

Ribbon for avalonia
MIT License
110 stars 24 forks source link

Data Binding Support #19

Open trommlbomml opened 3 years ago

trommlbomml commented 3 years ago

As far as I can see there is no support to populate the ribbon with MVVM? I mean creating pages, groups & items like buttons using viewmodels would be a great addition. I really like the way DevExpress support in their WPF solution:

View:

<Window>
    <Window.DataTemplates>
        <DataTemplate DataType="{x:Type RibbonTabViewModel}">
            <RibbonTab Header="{Binding TabHeaderText}" GroupsSource="{Binding Groups}" />
        </DataTemplate>

        <DataTemplate DataType="{x:Type RibbonTabGroupViewModel}>
            <RibbonGroupBox Header="{Binding GroupHeaderText}" ItemsSource="{Binding GroupItems}" />
        </DataTemplate>

         <DataTemplate DataType="{x:Type RibbonCommandViewModel}>
            <RibbonButton Header="{Binding Caption}" Command="{Binding}" />
        </DataTemplate>
    </Window.DataTemplates>
    <Ribbon TabItemsSource="{Binding TabItems}" />
</Window>

ViewModels:

public class RibbonViewModel : ViewModelBase
{
    public ObservableCollection<RibbonTabViewModel> TabItems { get; } = new ObservableCollection<RibbonTabViewModel>();
}

public class RibbonTabViewModel : ViewModelBase
{
    private string _tabHeaderText;

    public string TabHeaderText 
    {
        get => _tabHeaderText;
        set => SetValue(ref _tabHeaderText, value);
    }

    public ObservableCollection<RibbonTabGroupViewModel> GroupItems { get; } = new ObservableCollection<RibbonTabGroupViewModel>();
}

public class RibbonTabGroupViewModel : ViewModelBase
{
    private string _groupHeaderText;

    public string GroupHeaderText 
    {
        get => _groupHeaderText;
        set => SetValue(ref _groupHeaderText, value);
    }

    public ObservableCollection<ViewModelBase> GroupItems { get; } = new ObservableCollection<ViewModelBase>();
}

public class RibbonCommandViewModel : ViewModelBase, ICommand
{
    //.....
}

This would make this solution great for a lot of general purpose cases!

Splitwirez commented 3 years ago

I was not aware that there was a use case for generating the layout of the Ribbon dynamically. I appreciate the information you've provided about DevExpress's approach...I can't make any promises regarding results, but I will look into this at some point.

Could you elaborate on why one might want to generate the Ribbon's content dynamically in this way?

trommlbomml commented 3 years ago

Thank you for your fast answer! I come from the side where everything is defined and xaml without bindings, and after a certain size it is a mess to maintain and my proposal is a way to reduce friction. Here are some use cases which I really like to solve with this feature:

I think a similiar big control which I would expect to have this flexability is a dock-layout manager. From Code with bindings you have the freedom to simply create views by adding it to the viewmodel and not calling the view and break mvvm patterns.

Splitwirez commented 3 years ago

Thank you for your fast answer!

Not a problem :D

I come from the side where everything is defined and xaml without bindings, and after a certain size it is a mess to maintain and my proposal is a way to reduce friction. Here are some use cases which I really like to solve with this feature:

* Big ribbons are not any more a large xaml file or split up manually by user controls - you only have very few code to maintain for the ribbon

* Add/Remove Ribbon parts during Runtime easily - no converters or bool properties needed as the structure is represented as a viewmodel

* Make it easy to make an extensible, modular application:

  * each new module only needs to know the ribbon viewmodel and can extend the ribbon (DI ready)
  * If the module is not loaded, its parts are simply not added to the application

* Access Rights management/Visiblity of Ribbon Parts from the view model - I do not like to solve it in the view with a lot of bools scattered in the viewmodels

You raise a very good point. I hadn't considered any of these things...I'll see what I can do.

* Context-dependent visiblity in the ribbon like in office, simply handle it in the code, testable and better maintainable

Okay, that doesn't seem quite right - Contextual tabs in Microsoft Office (and other Ribbon apps) aren't just bog-standard Ribbon tabs made visible only when needed - they're placed into groups...and from my understanding, it's the visibility of those groups that changes, not that of the individual tabs within them. In fact, such Contextual tab groups are already implemented on this very repository's develop branch...though I fear that I may need to rethink how I've implemented them according to your suggestion.

...or have I misunderstood what you were referring to about "Context-dependent visibility"?

I think a similiar big control which I would expect to have this flexability is a dock-layout manager. From Code with bindings you have the freedom to simply create views by adding it to the viewmodel and not calling the view and break mvvm patterns.

I'm not quite sure what you mean by "dock-layout manager"...but I am curious now.

Also, does DevExpress's WPF Ribbon have a Quick Access Toolbar? And if so...are you at all familiar with how it manages adding/removing and saving/loading items in that Quick Access Toolbar?

trommlbomml commented 3 years ago

Okay, that doesn't seem quite right - Contextual tabs in Microsoft Office (and other Ribbon apps) aren't just bog-standard Ribbon tabs made visible only when needed - they're placed into groups...and from my understanding, it's the visibility of those groups that changes, not that of the individual tabs within them. In fact, such Contextual tab groups are already implemented on this very repository's develop branch...though I fear that I may need to rethink how I've implemented them according to your suggestion. ...or have I misunderstood what you were referring to about "Context-dependent visibility"?

Unfortunatly I cannot answer this, as I have almost no experience with the microsoft ribbon, only DevExpress. That's why I have added this point too. At least it would be great to have short examples for that in the documentation, then it maybe would be clearer if that really replace the original requirement.

I'm not quite sure what you mean by "dock-layout manager"...but I am curious now.

Something like this: Dock Layout Manager DevExpress

Also, does DevExpress's WPF Ribbon have a Quick Access Toolbar? And if so...are you at all familiar with how it manages adding/removing and saving/loading items in that Quick Access Toolbar?

Yes it has, see here. I did not took a look into the source code but I guess they solved it because they have a custom ribbon window. As far as I have read this control has this also? So you can add this the same way by having a Dependency Property to bind a list of e.g. QuickToolBarButtons to the Window?

Splitwirez commented 3 years ago

Unfortunatly I cannot answer this, as I have almost no experience with the microsoft ribbon, only DevExpress. That's why I have added this point too. At least it would be great to have short examples for that in the documentation, then it maybe would be clearer if that really replace the original requirement.

That's fine. Looks like my implementation isn't as far off from theirs as I would've expected. I will be adding proper documentation once the in-development features are...well, closer to stable/finalized.

Something like this: Dock Layout Manager DevExpress

Oh THAT...okay, that makes more sense now. Thanks.

Yes it has, see here. I did not took a look into the source code but I guess they solved it because they have a custom ribbon window. As far as I have read this control has this also? So you can add this the same way by having a Dependency Property to bind a list of e.g. QuickToolBarButtons to the Window?

Hm...well, mine has a custom window as well, though it's more for sake of convenience than a necessity. I'd imagine theirs is a similar deal, with the Quick Access Toolbar being in the titlebar and all that.

So who is in charge of saving whatever is in the Quick Access Toolbar, and loading it again the next time the application is opened? Is that built into the DevExpress Ribbon, or up to the application developer to implement?

trommlbomml commented 3 years ago

Yes, you have not any other good options to customize windows :-), perfect fit to implement it in that way.