Reducir / Controles de usuario visible en el botón Haga clic con MVVM - ningún mecanismo de intercambio -

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

  •  21-09-2019
  •  | 
  •  

Pregunta

En mi escenario Tengo un MainView + MainViewModel, UserControl1 + 2 UserControl. En el MainView tengo 2 botones etiquetados: Button_ShowUserControl1 + Button_ShowUserControl2. En la parte inferior de la MainView tengo un "ContentGrid" que tiene / should_take ... cada control de usuario.

Mi objetivo:

Cuando se hace clic en Button_ShowUserControl1 UserControl1 es Visible y UserControl2 o cualquier otro control de usuario se debe establecer en colapsado . Lo mismo es válido para Button_ShowUserControl2.

Mi problema:

1). Como los UserControls deberán cargarse en el inicio de la aplicación, ¿cómo puedo ponerlos todos juntos en el "ContentGrid"? Eso, en realidad no es posible ... ¿cómo puedo hacer un control de usuario visible mientras el otro está en el mismo lugar / "ContentGrid" acaba de derrumbarse?

2.) Como 1.) No parece posible, ¿cómo puedo crear una instancia de todos los UserControls al inicio de la aplicación y hacerlos accesibles solamente / abajo cuando se hace clic en el botón correspondiente?

3). Como un control de usuario tiene una propiedad Visibilidad = visible / oculto / colapsado, ¿cómo puede volver que se unen a una propiedad en un modelo de vista de un valor tal como se derrumbó? Sólo podía obtener un valor booleano como Visibilidad = verdadero / falso?

Mi 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;
        }  
    }        
}

Si el código es incorrecto, por lo tanto, le pido aquí:)

¿Fue útil?

Solución

Sólo tienen 2 cosas mal con este código.

1) No se puede establecer la visibilidad de un control de usuario directamente ... tienes que ponerlo en un recipiente:

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

2) La visibilidad no es un valor booleano, es una enumeración. Como tal, tendrá que utilizar un convertidor para convertir desde booleano a la visibilidad. Observe:

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

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

Eso debería ser éste. Espero que esto ayude.

Hay otras cosas que está saliendo de pistas acerca de que podría afectar a la capacidad de este para el trabajo. Por ejemplo, no se presenta el elemento contenedor más grande ... ¿estás envolviendo todo en un StackPanel? Si está envolviendo todo en una cuadrícula, por ejemplo, los controles superponer todo en capas.

Trate de estos cambios que propongo ... debe llegar más cerca.


Editar: Otra idea a partir de datos de plantillas

Otra cosa que podría hacer es asegurarse de que tiene un modelo de vista único para cada uno de estos puntos de vista que desea mostrar y ocultar:

public class MyFirstViewModel : ViewModel
{

}

public class MySecondViewModel : ViewModel
{

}

Luego de su "padre" o "principal" modelo de vista, mostrar u ocultar las vistas que desea en virtud de tener en una colección de ViewModels:

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

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

Para alambre todo para arriba en su opinión, usted entonces DataTemplate estos tipos con sus controles de usuario (pero esto no causa esos puntos de vista deberían ejecutarse a menos que se necesitaban:

<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>

Y para cualquier ViewModels usted pone en "ViewsToShow", la vista verá automáticamente que la plantilla y en la vista apropiada. De nuevo, sin crear instancias antes de que sea necesario.

Esto es probablemente un poco más limpio que poner todo cosa en la vista y el establecimiento de visibilidad, pero sería dependiente tiene un único tipo de vista de modelo para todas las vistas, que podría no ser el caso.


La cuestión de guardar el estado aparece cuando se utiliza el enfoque DataTemplated. La solución aquí es que pisar el modelo de vista como el estado del control y el diseño de sus dos ViewModels y sus Vistas en consecuencia. Aquí hay un ejemplo que permite que cambiar sus Vistas usando DataTemplating, pero el cambio de ida y vuelta guarda el estado.

Suponga que tiene la configuración de la última sección w / 2 ViewModels que tienen DataTemplates definidos. Vamos a cambio el MainViewModel un poco:

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;
     }
}

Y algunos cambios en la vista principal. He omitido los DataTemplates por razones de brevedad.

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

Eso es todo. El secreto aquí es que estoy ahorrando la referencia al modelo de vista original. De esta manera, digamos que es una propiedad de cadena en un modelo de vista y un cuadro de texto asociado en el usercontrol DataTemplated con un dos vías de unión a continuación, el estado esencialmente se guardará.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top