Réduire / Visible Contrôles utilisateur sur le bouton Cliquez avec MVVM - aucun mécanisme d'échange -

StackOverflow https://stackoverflow.com/questions/2097253

  •  21-09-2019
  •  | 
  •  

Question

Dans mon scénario j'ai un MainView + MainViewModel, UserControl1 + UserControl 2. Dans le MainView j'ai 2 boutons marqués: Button_ShowUserControl1 + Button_ShowUserControl2. Dans la partie inférieure de la MainView j'ai un « ContentGrid » qui prend / should_take ... chaque UserControl.

Mon but:

Lorsque Button_ShowUserControl1 clique sur UserControl1 Visible et UserControl2 ou tout autre UserControl doit être réglé sur Collapsed . La même chose est valable pour Button_ShowUserControl2.

Mon problème:

1.) Comme les UserControls doivent être chargés au démarrage de l'application comment puis-je les mettre tous ensemble dans une « ContentGrid »? Cest vraiment pas possible ... Comment puis-je faire un UserControl visible tandis que l'autre est dans le même lieu / « ContentGrid » juste effondré?

2). Comme 1.) ne semble pas possible comment puis-je instancier tous UserControls au début de l'application et de les rendre visibles que / Collapsed lorsque vous cliquez sur le bouton correspondant est?

3.) En tant que UserControl possède une propriété Visibilité = Visible / Invisible / Effondré, comment puis-je lier à une propriété dans un ViewModel retour d'une telle valeur comme Collapsed? Je ne pouvais obtenir une valeur booléenne comme Visibilité = false / true?

Mon TestCode:

<Grid x:Name="LayoutRoot" Background="#FFBDF5BD" ShowGridLines="False">
    <Grid.RowDefinitions>
        <RowDefinition Height="96*" />
        <RowDefinition Height="289*" />
    </Grid.RowDefinitions>      
    <Grid HorizontalAlignment="Stretch" Name="MenuGrid" VerticalAlignment="Stretch" Background="#FFCECEFF">
        <StackPanel Name="stackPanel1" Background="#FFEDFF00" Orientation="Horizontal">
            <Button Content="User Data 1" Height="35" Name="button1" Command="{Binding  Path=ShowUserControl1Command}" Width="150" Margin="100,0,0,0" />
            <Button Content="User Data 2" Height="35" Name="button2" Width="150" Margin="100,0,0,0" />
        </StackPanel>
    </Grid>
    <Grid Grid.Row="1" HorizontalAlignment="Stretch" Name="ContentGrid" VerticalAlignment="Stretch" Background="#FFB15454" />
</Grid>

<UserControl x:Class="SwapUserControls.MVVM.UserControl2"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:vm="clr-namespace:SwapUserControls.MVVM.ViewModel"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" Visibility="{Binding IsUserControl1Collapsed, Path=Value}">

<UserControl.Resources>
    <vm:MainViewModel x:Key="MainViewModelID" />
</UserControl.Resources>

<UserControl.DataContext>
    <Binding Source="{StaticResource MainViewModelID}" />
</UserControl.DataContext>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="228*" />
        <RowDefinition Height="72*" />
    </Grid.RowDefinitions>
    <Button Content="UserControl2" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="112,27,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
    <DataGrid HorizontalAlignment="Stretch" Name="dataGrid1" VerticalAlignment="Stretch" Background="#FFC046F8" />
</Grid>

public class MainViewModel : ViewModelBase
{
    RelayCommand _ShowUserControl1Command;
    private bool _IsUserControl1Collapsed;

    public RelayCommand ShowUserControl1Command
    {
        get
        {
            if (_ShowUserControl1Command == null)
            {
                _ShowUserControl1Command = new RelayCommand( () => ShowUserControl1() );                       
            }
            return _ShowUserControl1Command;
        }
    }

    public void ShowUserControl1()
    {
        _IsUserControl1Collapsed = true;
    }

    public bool IsUserControl1Collapsed 
    {          
        get
        {
            return _IsUserControl1Collapsed;
        }  
    }        
}

Oui, le code est erroné, donc je demande ici:)

Était-ce utile?

La solution

Vous avez seulement 2 mauvaises choses avec ce code.

1) Vous ne pouvez pas définir la visibilité d'un usercontrol directement ... vous devez le mettre sur un conteneur:

<Grid Visibility="Collapsed">
    <myControls:MyUserControl />
</Grid>

2) La visibilité est pas une valeur booléenne, il est un enum. En tant que tel, vous aurez besoin d'utiliser un convertisseur pour convertir booléenne Visibilité. Observez:

<Window ...>
<Window.Resources>
     <BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>

<Grid Visibility="{Binding ShouldShowUsercontrol1, Converter={StaticResource BoolToVis}}">
     <myControls:MyUserControl />
</Grid>
</Window>

Cela devrait l'être. Espérons que cela aide.

Il y a d'autres choses que vous quittez des indices sur qui pourraient affecter la capacité de cela fonctionne. Par exemple, vous ne vous présentez pas le plus gros élément conteneur ... êtes-vous tout emballage dans un StackPanel? Si vous envelopper tout dans une grille, par exemple, les contrôles recouvriront tout en couches.

Essayez ces changements que je propose ... il faut vous rapprocher.


Edit: Une autre idée en utilisant des modèles de données

Une autre chose que vous pouvez faire est que vous avez un ViewModel unique pour chacune de ces vues que vous souhaitez afficher et cacher:

public class MyFirstViewModel : ViewModel
{

}

public class MySecondViewModel : ViewModel
{

}

Ensuite, à partir de « parent » ou « principale » ViewModel, vous afficher ou masquer les vues que vous voulez en vertu de les avoir dans une collection de ViewModels:

public MyMainViewModel : ViewModel
{
     public ObservableCollection<ViewModel> ViewsToShow
     {
          ...
     }

     public void ShowFirstViewModel()
     {
          ViewsToShow.Add(new MyFirstViewModel());
     }
}

Pour câbler tout en vous, alors vous datatemplate ces types avec leurs contrôles utilisateur (mais cela ne cause pas ces vues à instancier si elles sont nécessaires:

<Window ...>
     <Window.Resources>
          <DataTemplate DataType="{x:Type myViewModels:MyFirstViewModel}">
               <myViews:MyFirstView />
          </DataTemplate>

          <DataTemplate DataType="{x:Type myViewModels:MySecondViewModel}">
               <myViews:MySecondView />
          </DataTemplate>
     </Window.Resources>

     <ItemsControl ItemsSource="{Binding ViewsToShow}" />

</Window>

Et pour tout ViewModels que vous mettez dans « ViewsToShow », le point de vue verra automatiquement dans la vue approprié et le modèle. Encore une fois, sans instancier avant qu'il ne soit nécessaire.

Ceci est probablement un peu plus propre que de mettre tout chose dans la vue et la mise en visibilité, mais il dépendra de vous avez un type de modèle de vue unique pour chaque point de vue, ce qui pourrait ne pas être le cas.


La question de l'état d'économie vient lors de l'utilisation de l'approche DataTemplated. La solution ici est de marcher votre ViewModel comme l'état du contrôle et de la conception à la fois vos ViewModels et vos vues en conséquence. Voici un exemple qui vous permet d'échanger vos vues à l'aide DataTemplating, mais le passage en arrière et sauve en avant l'état.

Supposons que vous avez la configuration de la dernière section w / 2 viewmodels qui ont DataTemplates définis. Changeons le MainViewModel un peu:

public MyMainViewModel : ViewModel
{
     public RelayCommand SwapViewsCommand
     {
          ...
     }

     public ViewModel View
     {
          ...
     }
     private ViewModel _hiddenView;
     public MyMainViewModel()
     {
          View = new MyFirstViewModel();
          _hiddenView = new MySecondViewModel();
          SwapViewsCommand = new RelayCommand(SwapViewModels);
     }

     public void SwapViewModels()
     {
          var hidden = _hiddenView;
          _hiddenView = View;
          View = hidden;
     }
}

Et quelques changements à la vue principale. J'ai omis les DataTemplates par souci de concision.

<Window ...>
     <!-- DataTemplates Here -->
     <Button Command="{Binding SwapViewsCommand}">Swap!</Button>
     <ContentControl Content="{Binding View}" />
</Window>

Voilà. Le secret ici est que je sauvegarde la référence au modèle de vue original. De cette façon, disons qu'il est une propriété de chaîne dans un viewmodel et une zone de texte associé dans la usercontrol DataTemplated avec dans les deux sens de liaison alors l'état sera essentiellement sauvegardé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top