在 mvvm 中显式保存

Posted

技术标签:

【中文标题】在 mvvm 中显式保存【英文标题】:explicit save in mvvm 【发布时间】:2013-04-15 11:37:17 【问题描述】:

我有一个包含员工详细信息(全名、年龄、职位)的网格和一个保存按钮。 我希望只有在按下保存按钮时才会保存员工。 如何在 MVVM 中实现它?

    <TextBlock
        Margin="3"
        Text="Full Name:"
        VerticalAlignment="Center"
        />
    <TextBox 
        Grid.Column="1"
        Margin="3"
        Text="Binding FullName, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True"
        />     
    <TextBlock
        Grid.Row="1"
        Margin="3"
        Text="Age:"
        VerticalAlignment="Center"
        />
    <TextBox 
        Grid.Column="1"
        Grid.Row="1"
        Margin="3"
        Text="Binding Age, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True"
        />
    <TextBlock
        Grid.Row="2"
        Margin="3"
        Text="Position:"
        VerticalAlignment="Center"
        />
    <TextBox 
        Grid.Column="1"
        Grid.Row="2"
        Margin="3"
        Text="Binding Position, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True"
        />


    <Button
        Grid.Row="4"
        Grid.ColumnSpan="2"
        Content="Save"
        Command="Binding SaveCommand"
        Width="80"
        Height="22"
        Margin="3"
        HorizontalAlignment="Right"
        VerticalAlignment="Bottom"
        />

我的 View 模型没有实现 Save 方法: 我不确定我知道如何处理显式绑定......

public string FullName
        
            get  return _emp.FullName; 
            set 
             
                _emp.FullName = value;
                OnPropertyChanged("FullName");
            
        

        public int Age
        
            get  return _emp.Age; 
            set 
             
                _emp.Age = value;
                OnPropertyChanged("Age");
            
        

        public string Position
        
            get  return _emp.Position; 
            set 
             
                _emp.Position = value;
                OnPropertyChanged("Position");
            
        


        public EmployeeViewModel(Employee emp)
        
            _emp = emp;

            _employees = new ObservableCollection<EmployeeViewModel>();

            if (_emp.Employees != null)
            
                foreach (Employee employee in _emp.Employees)
                    _employees.Add(new EmployeeViewModel(employee));
            
        

        public string[] ValidatedProperties =
        
            "FullName",
            "Age",
            "Position"
        ;

        public RelayCommand SaveCommand
        
            get
            
                return _saveCommand ??
                    (_saveCommand = new RelayCommand(Save, CanSave));
            
            set  _saveCommand = value; 
        

        private bool CanSave()
        
            foreach (string property in ValidatedProperties)
                if (!string.IsNullOrEmpty(GetValidationError(property)))
                    return false;

            return true;
        

        private void Save()
        
            throw new NotImplementedException();    
        

【问题讨论】:

关于DataAccess 层,您使用的是什么?使用EntityFramework 模型?或SQL adapter?或者您是否希望在单击保存命令时以编程方式将员工的 ListCollection 添加到网格中? 为什么要使用 UpdateSourceTrigger=Explicit? 简单列表 save 是什么意思?你的意思是从前端保存到ViewModel还是数据库? 到 viewModel 并最终到数据库(在这种情况下只是内存中的一个简单列表) 【参考方案1】:

经过一番挖掘,我发现了一些不错的技术,使用命令参数+转换器。 http://www.shujaat.net/2011/01/updatesourcetrigger-explicit-for-mvvm.html

所以在我的情况下:

    <TextBlock
        Margin="3"
        Text="Full Name:"
        VerticalAlignment="Center"
        />
    <TextBox 
        x:Name="FullNameTextBox"
        Grid.Column="1"
        Margin="3"
        Text="Binding FullName, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True"
        />     
    <TextBlock
        Grid.Row="1"
        Margin="3"
        Text="Age:"
        VerticalAlignment="Center"
        />
    <TextBox 
        x:Name="AgeTextBox"
        Grid.Column="1"
        Grid.Row="1"
        Margin="3"
        Text="Binding Age, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True"
        />
    <TextBlock
        Grid.Row="2"
        Margin="3"
        Text="Position:"
        VerticalAlignment="Center"
        />
    <TextBox  
        x:Name="PositionTextBox"
        Grid.Column="1"
        Grid.Row="2"
        Margin="3"
        Text="Binding Position, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True"
        />


    <Button
        Grid.Row="4"
        Grid.ColumnSpan="2"
        Content="Save"
        Command="Binding SaveCommand"
        Width="80"
        Height="22"
        Margin="3"
        HorizontalAlignment="Right"
        VerticalAlignment="Bottom"
        >
        <Button.CommandParameter>
            <MultiBinding Converter="StaticResource EmployeeConverter">
                <Binding ElementName="FullNameTextBox" Path="Text" />
                <Binding ElementName="AgeTextBox" Path="Text" />
                <Binding ElementName="PositionTextBox" Path="Text" />
            </MultiBinding>
        </Button.CommandParameter>
    </Button>
</Grid>

对 viewModel 的更改:

private RelayCommand<object> _saveCommand;


public RelayCommand<object> SaveCommand

    get
    
        return _saveCommand ??
            (_saveCommand = new RelayCommand<object>(Save, CanSave));
    
    set  _saveCommand = value; 


private bool CanSave(object value)

    foreach (string property in ValidatedProperties)
        if (!string.IsNullOrEmpty(GetValidationError(property)))
            return false;

    return true;


private void Save(object value)

    string[] parameters = ((string)value).Split(new char[]  ':' );
    FullName = parameters[0];
    Age = Convert.ToInt32(parameters[1]);
    Position = parameters[2];

还有小转换器:

public class EmployeeConverter : IMultiValueConverter

    public object Convert(object [] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        string fullName = (string)values[0];
        string age = (string)values[1];
        string position = (string)values[2];

        return string.Format("0:1:2", fullName, age, position);
    

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    
        throw new NotImplementedException();
    

【讨论】:

以上是关于在 mvvm 中显式保存的主要内容,如果未能解决你的问题,请参考以下文章

在 terraform 模块中显式使用提供程序

在 DataFrameMapper 中显式删除列

为啥在 Haskell 中显式推导 Show/Read?

为啥在 OpenGL 中显式管理矩阵更好?

在 QT 中显式调用paintGL

在 Java 中显式调用默认方法