mvvm - 使用 MVVM 单击按钮时折叠/可见用户控件 - 无交换机制 -

标签 mvvm user-controls collapse

在我的场景中,我有一个 MainView + MainViewModel、UserControl1 + UserControl 2。
在 MainView 中,我有 2 个按钮标记为:Button_ShowUserControl1 + Button_ShowUserControl2。
在 MainView 的下部,我有一个“ContentGrid”,它采用/should_take...每个用户控件。

我的目标:

单击 Button_ShowUserControl1 时 用户控制1 可见用户控件2 或任何其他 UserControl 必须设置为 已折叠 .同样适用于 Button_ShowUserControl2。

我的问题:

1.) 由于用户控件应在应用程序启动时加载,我怎样才能将它们全部放在一个“ContentGrid”中?这实际上是不可能的......那么我怎样才能让一个 UserControl 可见而另一个在同一个地方/“ContentGrid”刚刚折叠?

2.) 作为 1.) 似乎不可能我如何在应用程序启动时实例化所有 UserControls 并在单击相应按钮时使它们仅可见/折叠?

3.) 由于 UserControl 有一个属性 Visibility = Visible/Hidden/Collapsed,我怎样才能绑定(bind)到 ViewModel 中的属性返回像 Collapsed 这样的值?我只能得到像 Visibility = false/true 这样的 bool 值?

我的测试代码:

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

是的,代码是错误的,所以我在这里问:)

最佳答案

这段代码只有两件事有问题。

1) 您不能直接设置用户控件的可见性...您必须在容器上设置它:

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

2)可见性不是 bool 值,它是一个枚举。因此,您需要使用转换器将 bool 值转换为可见性。观察:
<Window ...>
<Window.Resources>
     <BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>

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

应该是这样的。希望这可以帮助。

还有其他一些你留下的线索可能会影响它的工作能力。例如,您没有显示最大的容器元素......您是否将所有内容都包装在 StackPanel 中?例如,如果您将所有内容包装在 Grid 中,则控件将覆盖所有内容。

试试我建议的这些改变......它应该让你更接近。

编辑:使用数据模板的另一个想法

您可以做的另一件事是确保您对要显示和隐藏的每个 View 都有一个唯一的 ViewModel:
public class MyFirstViewModel : ViewModel
{

}

public class MySecondViewModel : ViewModel
{

}

然后从您的“父”或“主” View 模型中,您可以通过将 View 模型放在集合中来显示或隐藏所需的 View :
public MyMainViewModel : ViewModel
{
     public ObservableCollection<ViewModel> ViewsToShow
     {
          ...
     }

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

要将 View 中的所有内容连接起来,您可以使用它们的用户控件对这些类型进行数据模板化(但这不会导致这些 View 被实例化,除非需要它们:
<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>

对于您放入“ViewsToShow”的任何 ViewModel, View 将​​自动在适当的 View 中看到该 View 和模板。同样,无需在需要之前实例化它。

这可能比将所有东西都放在 View 中并设置可见性要干净一些,但这取决于您对每个 View 都有一个唯一的 View 模型类型,但情况可能并非如此。

使用 DataTemplated 方法时会出现保存状态的问题。这里的解决方案是将您的 ViewModel 作为控件的状态,并相应地设计您的 ViewModel 和您的 View 。这是一个允许您使用 DataTemplating 交换 View 的示例,但来回切换会保存状态。

假设您有上一节中的设置,其中包含定义了数据模板的 2 个 View 模型。让我们稍微改变一下 MainViewModel:
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;
     }
}

并对主视图进行了一些更改。为简洁起见,我省略了 DataTemplates。
<Window ...>
     <!-- DataTemplates Here -->
     <Button Command="{Binding SwapViewsCommand}">Swap!</Button>
     <ContentControl Content="{Binding View}" />
</Window>

就是这样。这里的 secret 是我保存了对原始 View 模型的引用。这样,假设在 View 模型中有一个字符串属性,在 DataTemplated 用户控件中有一个关联的文本框,带有 。双向绑定(bind) 那么状态将基本上被保存。

关于mvvm - 使用 MVVM 单击按钮时折叠/可见用户控件 - 无交换机制 -,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2097253/

相关文章:

mvvm - MvvmCross:如何在Android上从常规 View 导航到Mvvm View 模型?

c# - 将 UserControl 中元素的属性绑定(bind)到 MyViewModel.cs 中的属性

wpf - 从 View 模型强制 wpf 控件更新

c# - Silverlight4 + C# : Using INotifyPropertyChanged in a UserControl to notify another UserControl is not notifying

html - 在 Bootstrap 3 中隐藏切换导航栏

R - 按行折叠

c# - 绑定(bind)到模型或 View 模型

在 UserControl 中使用依赖属性的 wpf 问题

jquery - Div 折叠更改位置

c# - 如何在mvvm中绑定(bind)鼠标双击命令