C# MVVM数据网格,用户可以在其中添加行。在所有字段都有效之前不要添加
我有一个WPF数据网格,用户可以在其中添加行。我希望它在输入某些必需的单元格之前不添加新行 e、 g 我的数据网格有以下列,C# MVVM数据网格,用户可以在其中添加行。在所有字段都有效之前不要添加,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个WPF数据网格,用户可以在其中添加行。我希望它在输入某些必需的单元格之前不添加新行 e、 g 我的数据网格有以下列,名字,姓氏,年龄,职务,薪水 当我通过datagrid输入新行时,我只需输入FirstName,我的集合中就有了一个只设置了FirstName的新模型。在输入名字、姓氏和年龄之前,我不想添加新型号 我的型号: public sealed class Foo { public Foo() { } public Foo(string firstN
名字
,姓氏
,年龄
,职务
,薪水
当我通过datagrid输入新行时,我只需输入FirstName
,我的集合中就有了一个只设置了FirstName
的新模型。在输入名字
、姓氏
和年龄
之前,我不想添加新型号
我的型号:
public sealed class Foo
{
public Foo()
{
}
public Foo(string firstName, string surname, int age)
{
Age = age;
FirstName = firstName;
Surname = surname;
}
[Required]
public int Age { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string Surname { get; set; }
public string JobTitle { get; set; }
public decimal Salary { get; set; }
}
视图模型
internal sealed class MainViewModel : ViewModelBase
{
private ObservableCollection<Foo> _foos = new ObservableCollection<Foo>();
private IDataService _dataService;
private Foo _selectedFoo;
public RelayCommand ButtonClickCommand { get; private set; }
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
Foos = _dataService.Foos();
RegisterCommands();
}
public void RegisterCommands()
{
ButtonClickCommand = new RelayCommand(
ButtonClick,
() => true);
}
public ObservableCollection<Foo> Foos
{
get { return _foos; }
set
{
if (_foos == value) return;
_foos = value;
RaisePropertyChanged();
}
}
public Foo Foo
{
get { return _selectedFoo; }
set
{
if (_selectedFoo == value) return;
_selectedFoo = value;
RaisePropertyChanged();
}
}
private void ButtonClick()
{
}
}
现在,我的DataGrid
如下所示:
<DataGrid Grid.Row="0"
Grid.Column="0"
AutoGenerateColumns="False"
ItemsSource="{Binding Foos, ValidatesOnExceptions=True}"
CanUserAddRows="True"
SelectedItem="{Binding Foo}">
<DataGrid.RowValidationErrorTemplate>
<ControlTemplate>
<Grid Margin="0,-2,0,-2"
ToolTip="{Binding RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}">
<Ellipse StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}" />
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
<DataGrid.RowValidationRules>
<validation:FooValidationRule ValidationStep="UpdatedValue" ValidatesOnTargetUpdated="True"/>
</DataGrid.RowValidationRules>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding (model:Foo.Age), ValidatesOnExceptions=True}" Header="Age" />
<DataGridTextColumn Binding="{Binding (model:Foo.FirstName), ValidatesOnExceptions=True}" Header="First Name"/>
<DataGridTextColumn Binding="{Binding (model:Foo.Surname), ValidatesOnExceptions=True}" Header="Surname"/>
<DataGridTextColumn Binding="{Binding (model:Foo.JobTitle), ValidatesOnExceptions=True}" Header="Job Title"/>
<DataGridTextColumn Binding="{Binding (model:Foo.Salary), ValidatesOnExceptions=True}" Header="Salary"/>
</DataGrid.Columns>
</DataGrid>
但是,即使行处于无效状态,它仍然会向绑定的
Foos
集合添加一个新的Foo
。我过去这样做的一种方法是使用一个带有弹出对话框的“添加”按钮。在此对话框中设置字段,然后有一个“保存”-“取消”按钮。然后,您可以在保存时进行验证,然后单击并提交到datagrid。好了,验证只是向用户指示他们是否输入了有效的数据,它并不控制提交数据。我有两个列表。一个用于UI的列表和一个持久化的列表,一旦这些列表有效,我将把它们从UI列表移动到持久化列表。凌乱的我也喜欢你的想法,但必须通过datagrid输入:(这仍然不是最糟糕的事情。请记住,您的viewmodel充当视图到模型的中间层。您可以在viewmodel中有临时或中间层列表,并且只有在保存类型操作或某些触发器上,数据才会返回到实际模型。它并不总是很漂亮,但这就是开发:)。我过去这样做的一种方法是,有一个“添加”按钮,它有一个弹出的对话框。在这个对话框中,您可以设置字段,然后有一个“保存”-“取消”按钮。然后,您可以在保存时单击并提交到datagrid进行验证。好了,验证只是向用户指示他们是否输入了有效数据,它并不控制数据的提交。我有两个列表。一个列表用于UI,另一个列表用于持久化,我正在将内容从UI列表移动到持久化列表一旦它有效。混乱。我也喜欢你的想法,但它必须通过datagrid输入,不幸的是:(这仍然不是最糟糕的事情。请记住,您的viewmodel充当视图到模型的中间层。您可以在viewmodel中有临时或中间层列表,并且只有在保存类型操作或某些触发器上,数据才会返回到实际模型。它并不总是漂亮的,但这就是开发:)。
public sealed class FooValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (((BindingGroup) value)?.Items.Count == 0)
{
IsValid = true;
return new ValidationResult(true, null);
}
if (!(((BindingGroup) value)?.Items[0] is Foo foo))
{
IsValid = false;
return new ValidationResult(false, "Error");
}
if (string.IsNullOrWhiteSpace(foo.FirstName))
{
IsValid = false;
return new ValidationResult(false, "Must enter a First Name");
}
if (string.IsNullOrWhiteSpace(foo.Surname))
{
IsValid = false;
return new ValidationResult(false, "Must enter a Surname");
}
if (foo.Age == 0)
{
IsValid = false;
return new ValidationResult(false, "Must enter age");
}
IsValid = true;
return new ValidationResult(true, string.Empty);
}
public bool IsValid { get; set; }
}
<DataGrid Grid.Row="0"
Grid.Column="0"
AutoGenerateColumns="False"
ItemsSource="{Binding Foos, ValidatesOnExceptions=True}"
CanUserAddRows="True"
SelectedItem="{Binding Foo}">
<DataGrid.RowValidationErrorTemplate>
<ControlTemplate>
<Grid Margin="0,-2,0,-2"
ToolTip="{Binding RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type DataGridRow}},
Path=(Validation.Errors)[0].ErrorContent}">
<Ellipse StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}" />
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
<DataGrid.RowValidationRules>
<validation:FooValidationRule ValidationStep="UpdatedValue" ValidatesOnTargetUpdated="True"/>
</DataGrid.RowValidationRules>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding (model:Foo.Age), ValidatesOnExceptions=True}" Header="Age" />
<DataGridTextColumn Binding="{Binding (model:Foo.FirstName), ValidatesOnExceptions=True}" Header="First Name"/>
<DataGridTextColumn Binding="{Binding (model:Foo.Surname), ValidatesOnExceptions=True}" Header="Surname"/>
<DataGridTextColumn Binding="{Binding (model:Foo.JobTitle), ValidatesOnExceptions=True}" Header="Job Title"/>
<DataGridTextColumn Binding="{Binding (model:Foo.Salary), ValidatesOnExceptions=True}" Header="Salary"/>
</DataGrid.Columns>
</DataGrid>