【问题标题】:MVVM Manipulating the view, using code-behind or viewmodelMVVM 操作视图,使用代码隐藏或视图模型
【发布时间】:2017-02-07 08:31:50
【问题描述】:

我正在使用 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>

代码隐藏为空。 这是我的 ViewModel:

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

和 ViewModel:

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 模式有什么更好的方法?

【问题讨论】:

    标签: c# wpf xaml mvvm


    【解决方案1】:

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

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

    在视图模型中包含这些仅用于视图的数据会使它变得杂乱无章,如果您的视图有点复杂,它可能会变得非常糟糕。对我来说,这有点违背了分离所有层并保持一切尽可能干净的意义。

    【讨论】:

    • 感谢您的回答。由于我缺乏经验,看起来我只是找不到这两种解决方案的优点/缺点。哪种方法更适合维护?我知道内部视图数据的可怕视图模型 bc 听起来并不好,但是我知道代码隐藏中没有任何内容。艰难的决定。
    • 代码隐藏并不邪恶;它可以而且应该使用,特别是在您的情况下,这是一种化妆品。它不应该用于数据操作、逻辑以及视图模型所做的所有事情。
    • 再次感谢您,我会去寻求第二个解决方案。
    • 一些需要考虑的事情:1) 后面的代码不容易进行单元测试。 2)如果不重新执行逻辑,您就无法用不同的视图替换您的视图。 3)如果您需要扩展功能,您可能会在视图中进行,而不是重构所有内容,因此设计往往不易维护。
    • 好的,但是我希望代码隐藏只关心视图,例如在单击按钮后滑动一些控件。即使它在视图模型中也无法测试。使用第一种方法,viewmodel 具有仅用于在视图中显示控件的属性,因此,如果我更改视图,我将拥有具有无论如何都不会使用的属性的视图模型,因为它仅与视图相关。我应该关心这个吗?
    【解决方案2】:

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

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

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

    【讨论】:

    • 感谢您的回答。例如,是否应该在代码隐藏或视图模型中使用文本框文本过滤列表?因为它只是展示我认为它也应该在代码隐藏中发生。对吗?
    • 是的,当用户在文本框中输入内容(或单击按钮)时,您应该创建一个事件处理程序,以根据输入的文本过滤列表项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多