Search code examples
c#windows-community-toolkitwinui-3

Switch DetailsTemplate in ListDetailsView between view and edit mode


I do have a ListDetailsView showing some data (lets say Company as a simple example here). Normally the details of a Company are shown as readonly. However, via the ListDetailsView.DetailsCommandBar it is possible to edit a Company (and also add a new Company). A clear separation between view and edit mode seems to be a good choice for the UI. I'm using a UserControl to show details of a Company.

So here are my questions:

  1. Where should the differentiation between view- and edit-mode happen? I thought it is a good idea to have a CompanyDetailsControl and a CompanyDetailsEditControl and select between the two (both using the same CompanyDetailsViewModel). There are other solutions as well, for example, the CompanyDetailsControl could handle the edit- and view-mode internally.
  2. Assuming that it is a good idea to switch between two UserControl, how can that be realized with the ListDetailsView.DetailsTemplate? I though it would be easy to use a DataTemplateSelector here, but that is only available for the ItemTemplate.

Not sure what code to provide to clarify my questions. So in case you need any code to better understand my question please leave a comment.


Solution

  • Note: I have never worked with UWP app, only applying MVVM pattern from WPF.


    Straight line where the split should happen is not drawn. It often depends on the developer himself, which framework is used and more.

    Me personally would go in way where UI handles UIs' things and ViewModel handles data only. That means the view is responsible for showing you the controls you are expecting to see/control the application. And when the view learns that property was changed, it should update how it looks.

    Since the point we know the app will have edit & readonly modes, we should prepare all necessary UI components (UserControls, Pages, ...) to handle both those states. They would be binded to ViewModel that have base in BaseViewModel that already have this edit variable inside. So that each UI component know it can work with that.

    Base view model:

    abstract class BaseViewModel : INotifyPropertyChanged
    {
        private string mIsInEditMode;
        public string IsInEditMode
        {
            get { return mIsInEditMode; }
            set
            {
                if(mIsInEditMode == value) return;
    
                mIsInEditMode = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(IsInEditMode));
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }
    

    All "normal" ViewModels inherit from it:

    class CompanyViewModel : BaseViewModel
    { /* props and logic of company */ }
    

    UI component (UserControl) would have either trigger (<Style.Triggers/>) or binded properties Visibility and IsEnabled to the BaseViewModel. Those bindings would handle this logic of showing/hiding and you have potential to control whole layouts, hide controls etc.

    <UserControl d:DataContext="{x:Bind local:CompanyViewModel}">
      <UserControl.Resources>
          <local:BoolInverterConverter x:Key="BoolInvert"/>
      </UserControl.Resources>
    
      <Grid>
    
         <Grid IsVisible="{Binding IsInEditMode}" IsEnabled="{Binding IsInEditMode}">
           <!-- Controls for edit mode -->
         </Grid>
    
         <Grid IsVisible="{Binding IsInEditMode, Converter={StaticResource BoolInvert}}"
               IsEnabled="{Binding IsInEditMode, Converter={StaticResource BoolInvert}}">
           <!-- Controls for readonly mode -->
         </Grid>
    
      </Grid>
    </UserControl>
    

    Note: I've used property IsVisible, You would actually use Visibility with some custom converter.