firstfloorsoftware / mui

Modern UI for WPF
Microsoft Public License
2.6k stars 755 forks source link

How to Navigate to Detail View from a List View. #179

Open Athuruga opened 6 years ago

Athuruga commented 6 years ago

I have got a List view with a Grid representing a list of customers. When I click on one of the rows a "Show Details Button" gets enabled. If a user clicks this Button I would like to navigate from the List View to the Details View of the customer and when I click on Close button at the customer details I would like to Navigate back to the List of Customers view. How can I pass the selected Customer to my Details View and how can I Navigate back and forth?

I'm able to get this done using pure WPF by having the Main Window reflecting a "Current View" and when I click the Buttons I assign the List or the Details View as current view. But I don't know how to resolve this with Modern UI.

rychlym commented 4 years ago

Hello, For a longer time no answer, so perhaps following could help.... (the solution is based on the ModernFrame element)

I had a similar navigation problem to solve. It was little simpler - just showing a pie chart based on data selected in the tree view (in case of no adequate data selected showing just some default pie chart). Perhaps it will bring an idea how to solve your problem.

I have used the ModernFrame element, with its: 1) Source property bound the data based on selected item from the tree view (with own so called UriConverter (try to convert null, string, int.ToString or GetHashCode().ToString() to relative Uri in descending order). 2) ContentLoader property bound to own FigurePieContentLoader - which is instantiated once and have all needed properties for needed for retrieving the UserControl to be navigated to - especially the correct selected item from the tree view, which is going to be passed as the data context to the being retrieved view - here is the passing data to the view. Note in case the value is null, the content loader instantiate the a different control. (This could be similar to situation to determine whether to instantiate Master view or the detail view ...).

Command bound to tree view changed selection determines the right data to show and set it in the the FigurePieContentLoader and then in the view model it self - in that property bound to the ModernFrame's Source property. This makes the ModernFrame trying to refresh, which call the content loader to get the view. (just an additional note: It seems to be using its own cache for already used Source values, so the content loaded is not called each time, the source is changed).

XAML part:

    <mui:ModernFrame
        ContentLoader="{Binding Path=FigurePieContentLoader}"
        Source="{Binding Path=ChartFigure, Converter={StaticResource ResourceKey=uriCnv}}" />

The view model part:

    public ViewModel()
    {
        // the ViweModel's ctor 
        // a  different initialization code...
        // ...

        // the update chart command
        this.UpdateChartCommand = new RelayCommand<PermutationTreeNode<string>>(UpdateChart);
    }

    private PermutationTreeNode<string> chartFigure;
    public PermutationTreeNode<string> ChartFigure
    {
        get => chartFigure;
        set => Set(ref chartFigure, value, nameof(ChartFigure));
    }

    private FigurePieContentLoader figurePieContentLoader = new FigurePieContentLoader();
    public FigurePieContentLoader FigurePieContentLoader => this.figurePieContentLoader;

    private void UpdateChart(PermutationTreeNode<string> node)
    {
            // a code to determine the primNode .......
            if (primNode != this.chartFigure)
            {
                this.FigurePieContentLoader.ChartFigure = primNode;
                this.ChartFigure = primNode;                            // leads to refresh the pie chart
            }
        }
    }

The content loader:

public class FigurePieContentLoader : DefaultContentLoader
{
    public PermutationTreeNode<string> ChartFigure { get; set; }

    protected override object LoadContent(Uri uri)
    {
        if (this.ChartFigure == null) return new DefaultPie();
        var view = new FigurePie() { DataContext = this.ChartFigure };
        return view;
    }
}

The UriConverter:

public class UriConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {

        string str = null;
        if (value == null)
        {
            str = "null";
        }
        else if (value is string valStr)
        {
            str = valStr;
        }
        else if (value is int valInt)
        {
            str = valInt.ToString();
        }
        else
        {
            str = value.GetHashCode().ToString();
        }
        return new Uri(str, UriKind.Relative);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException("UriConverter Convert Back is not supported!");
    }