MVVM 使用代码隐藏或视图模型操作视图



我正在使用MVVM编写应用程序,我有一个问题,如果我应该使用代码隐藏来操作View,还是应该将其留空。我想做的是,当用户单击按钮时,隐藏的视图会滑出。目前,我正在视图模型中执行此操作。这是我的代码:

这是我的观点:

<Window.DataContext>
        <ViewModels:MainWindowViewModel/>
    </Window.DataContext>
    <Window.Resources>
    <Style x:Key="DockPanelStyle" TargetType="{x:Type DockPanel}" >
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="Background" Value="AliceBlue"/>
        <Style.Triggers>
            <DataTrigger 
                         Binding="{Binding showView}" 
                         Value="true">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ThicknessAnimation
                                                Storyboard.TargetProperty="Margin" 
                                                To="0,0,0,0" 
                                                AccelerationRatio=".25" 
                                                DecelerationRatio=".25" 
                                                Duration="0:0:0.5" 
                                                 />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ThicknessAnimation
                                                Storyboard.TargetProperty="Margin" 
                                                To="0,0,-400,0" 
                                                DecelerationRatio=".25" 
                                                AccelerationRatio=".25" 
                                                Duration="0:0:0.5" 
                                                />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.ExitActions>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <StackPanel
            Grid.Column="0">
            <Label Content="Main view" HorizontalAlignment="Center" FontSize="42"/>
            <Button Command="{Binding SlideOutCommand}" Content="Show view" FontSize="42"/>
        </StackPanel>
        <DockPanel
            Grid.Column="1"
            Margin="0,0,-400,0"
            Style="{StaticResource DockPanelStyle}">
            <Label Content="Sliding view" HorizontalAlignment="Center" FontSize="42"/>
        </DockPanel>
    </Grid>
</Window>

代码隐藏为空。这是我的观点模型:

public class MainWindowViewModel : INotifyPropertyChanged
    {    
        public MainWindowViewModel()
        {
            showView = false;
        }
        public ICommand SlideOutCommand
        {
            get { return new ActionCommand(action => ShowView()); }
        }
        private void ShowView()
        {
            showView = true;
            //Do some extra logic
        }
        private bool _showView;
        public bool showView
        {
            get { return _showView; }
            set
            {
                _showView = value;
                OnPropertyChanged();
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        virtual protected void OnPropertyChanged([CallerMemberName]string propName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }

    }

或者我应该采用这样的解决方案:

视图:

 <Window.DataContext>
        <ViewModels:MainWindowViewModel/>
    </Window.DataContext>
    <Window.Resources>
    <Style x:Key="DockPanelStyle" TargetType="{x:Type DockPanel}" >
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="Background" Value="AliceBlue"/>
        <Style.Triggers>
            <DataTrigger 
                         Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" 
                         Value="true">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ThicknessAnimation
                                                Storyboard.TargetProperty="Margin" 
                                                To="0,0,0,0" 
                                                AccelerationRatio=".25" 
                                                DecelerationRatio=".25" 
                                                Duration="0:0:0.5" 
                                                 />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ThicknessAnimation
                                                Storyboard.TargetProperty="Margin" 
                                                To="0,0,-400,0" 
                                                DecelerationRatio=".25" 
                                                AccelerationRatio=".25" 
                                                Duration="0:0:0.5" 
                                                />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.ExitActions>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <StackPanel
            Grid.Column="0">
            <Label Content="Main view" HorizontalAlignment="Center" FontSize="42"/>
            <Button Command="{Binding SlideOutCommand}" Content="Show view" FontSize="42" Click="Button_Click"/>
        </StackPanel>
        <DockPanel
            x:Name="SlideView"
            Grid.Column="1"
            Margin="0,0,-400,0"
            Style="{StaticResource DockPanelStyle}"
            Tag="{Binding Path=showView,RelativeSource={RelativeSource AncestorType=Window}}">
            <Label Content="Sliding view" HorizontalAlignment="Center" FontSize="42"/>
        </DockPanel>
    </Grid>
</Window>

代码隐藏:

public partial class MainWindowView : Window, INotifyPropertyChanged
    {
        public MainWindowView()
        {
            InitializeComponent();
            showView = false;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            showView = true;
        }
        private bool _showView;
        public bool showView
        {
            get { return _showView; }
            set
            {
                _showView = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        virtual protected void OnPropertyChanged([CallerMemberName]string propName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }
    }

和视图模型:

public class MainWindowViewModel : INotifyPropertyChanged
    {
        public MainWindowViewModel()
        {
        }
        public ICommand SlideOutCommand
        {
            get { return new ActionCommand(action => ShowView()); }
        }
        private void ShowView()
        {
            //Do some extra logic
        }

        public event PropertyChangedEventHandler PropertyChanged;
        virtual protected void OnPropertyChanged([CallerMemberName]string propName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }

    }

MVVM 模式中更好的方法是什么?

有些人会告诉你,ViewModel 与模型和视图交互,但我不是其中之一。

如果你要做的纯粹是装饰性的,不依赖于任何模型数据,我会说你应该只在视图及其代码隐藏中处理它。

在视图

模型中拥有这些仅查看数据会使它变得混乱,如果你的视图有点复杂,它可能会变得非常糟糕。对我来说,这有点违背了分离所有层并保持一切尽可能干净的观点。

对我来说,ViewModel 应该处理与数据相关的任何逻辑。例如:

public class OrderViewModel
{
   /*
     Other fields and properties 
   */
   public decimal Total
   {
      get 
      {
         return this.Price * this.Quantity;
      }
   }
}

此处,ViewModel 包含用于计算订单总价的逻辑。但是任何视觉表示都不应该在这里。数据的可视化表示形式应该在视图中,而不是其他任何地方。

最新更新