MahApps / MahApps.Metro

A framework that allows developers to cobble together a better UI for their own WPF applications with minimal effort.
https://mahapps.com
MIT License
9.33k stars 2.44k forks source link

Make MA.M more MVVM-friendly #999

Closed AzureKitsune closed 9 years ago

AzureKitsune commented 10 years ago

There are some things in our library that can be made for or improved for MVVM scenarios. We should try to figure out how to make those non-friendly sections more friendly. (Feel free to discuss here or in gitter.)

zeluisping commented 10 years ago

Off-Topic: issue number 999

Gimly commented 10 years ago

Opening a Flyout is relatively complex in a MVVM scenario. For the record, how I did it in my project:

Works very nicely but you have to know how to use Caliburn's event aggregator.

robertstefan commented 10 years ago

Way to complicated ... especially for one that just begins using/learning MVVM ... :unamused:

remcoros commented 10 years ago

Here are some code samples from my app to get you started, Note that this uses Caliburn.Micro

Interface common to all flyout viewmodels (probably best to make an abstract base class for convenience)

public interface IFlyout : IScreen
{
    string Header { get; set; }

    bool IsOpen { get; set; }

    Position Position { get; set; }

    string Name { get; set; }

    bool IsModal { get; set; }
}

Flyout definiton in your MetroWindow:

<metro:MetroWindow.Flyouts>
    <metro:FlyoutsControl Name="Flyouts">
        <metro:FlyoutsControl.Template>
            <ControlTemplate>
                <Grid>
                    <ItemsPresenter />
                </Grid>
            </ControlTemplate>
        </metro:FlyoutsControl.Template>
        <metro:FlyoutsControl.ItemContainerStyle>
            <Style BasedOn="{StaticResource {x:Type metro:Flyout}}"
                   TargetType="{x:Type metro:Flyout}">
                <Setter Property="Header"
                        Value="{Binding Header}" />
                <Setter Property="IsOpen"
                        Value="{Binding IsOpen}" />
                <Setter Property="Position"
                        Value="{Binding Position}" />
                <Setter Property="IsModal"
                        Value="{Binding IsModal}" />
            </Style>
        </metro:FlyoutsControl.ItemContainerStyle>
    </metro:FlyoutsControl>
</metro:MetroWindow.Flyouts>

Inside your metro windows's viewmodel (e.g. shell):

    #region Flyouts
    public void ToggleFlyout(string name)
    {
        this.ApplyToggleFlyout(name);
    }

    public void ToggleFlyout(string name, Position position)
    {
        this.ApplyToggleFlyout(name, position);
    }

    public void ToggleFlyout(string name, bool isModal)
    {
        this.ApplyToggleFlyout(name, null, isModal);
    }

    public void ToggleFlyout(string name, Position position, bool isModal)
    {
        this.ApplyToggleFlyout(name, position, isModal);
    }

    protected void ApplyToggleFlyout(string name, Position? position = null, bool? isModal = null, bool? show = null)
    {
        Contract.Requires(name != null, "name cannot be null");
        foreach (var f in this.flyouts.Where(x => name.Equals(x.Name)))
        {
            if (position.HasValue)
            {
                f.Position = position.Value;
            }

            if (isModal.HasValue)
            {
                f.IsModal = isModal.Value;
            }

            if (show.HasValue)
            {
                f.IsOpen = show.Value;
            }
            else
            {
                f.IsOpen = !f.IsOpen;
            }
        }
    }

    #endregion

Here's how to use caliburn attached messages to call the toggleflyout methods:

            <MenuItem Header="APPLICATION">
                <MenuItem Header="Settings..."
                          cal:Message.Attach="[Event Click] = [Action ToggleFlyout('settings', 'Left', 'true')]"></MenuItem>
                <Separator></Separator>
                <MenuItem Header="Exit"
                          cal:Message.Attach="ExitToDesktop"></MenuItem>
            </MenuItem>
flagbug commented 10 years ago

Here is my (possibly not constructive) input on this issue: MahApps.Metro is a UI library, we shouldn't care if the user uses MVVM, MVC, what-have-you. The End.

punker76 commented 10 years ago

@flagbug :+1:

QuantumDeveloper commented 10 years ago

@flagbug if WPF developers in MS also thought so, then we never see controls with binding support and other cool features.

thoemmi commented 10 years ago

I'm with @flagbug, MA.M is an UI library and should be agnostic to any MVVM, MVC, whatever framework. @QuantumDeveloper: Every control should support binding, no doubt. Beyond that, do you have any practical suggestions how to make MA.M more MVVM friendly?

papuashu commented 10 years ago

I guess, in order to combine the two worlds, the best would be to create a library MA.M + Caliburn.Micro

dealproc commented 9 years ago

Can a contrib project be launched, now that MahApps is in v1.0 stage, that folks can start dumping what they've done to solve common problems in the MVVM space (e.g. showing a dialog via an IDialogManager) in some sort of way that makese sense?

thoemmi commented 9 years ago

I've started with my own (opiniated) MVVM library based on MahApps.Metro, see TinyLittleMvvm. It still lacks some documenation though.

papuashu commented 9 years ago

Meantime, I've discovered Caliburn.Metro which seems to be a good start in this direction (Caliburn.Micro + MA.M)

dealproc commented 9 years ago

link @papuashu ?

keithrfung commented 9 years ago

@dealproc Caliburn.Metro

bhaidar commented 7 years ago

@remcoros I might be missing something in here. Where do you specify the UserControl that should appear inside the Flyout? In case of multiple Flyouts, how do you specify that? Thanks