我想验证我的DataGrid
行是否有错误,如果存在任何错误,则应禁用“保存”按钮,或者至少应该有一些消息指出存在错误。
经过一番研究,我偶然发现了以下帖子:Detecting WPF Validation Errors
该帖子提供了解决方案,可以使用这段代码来验证错误的DataGrid:
private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = IsValid(sender as DependencyObject);
}
private bool IsValid(DependencyObject obj)
{
// The dependency object is valid if it has no errors and all
// of its children (that are dependency objects) are error-free.
return !Validation.GetHasError(obj) &&
LogicalTreeHelper.GetChildren(obj)
.OfType<DependencyObject>()
.All(IsValid);
}
但是,我正在为按钮使用ICommand
实现,但似乎无法弄清楚如何使用它实现IsValid
函数。我使用DependencyObject
和其他方法尝试了几种方法来注册Binding
。
任何人都可以向我指出正确的方向,我想这应该很简单,但我只是无法理解。
在我的按钮的实现下方:
public class MyViewModel
{
public ICommand MyCommandButton { get; set; }
public MyViewModel()
{
MyCommandButton = new BaseCommand(MyCommandFunction);
this.Initialize();
}
private void MyCommandFunction(object obj)
{
//... some (not yet implemented) logic
}
public class BaseCommand : ICommand
{
private Predicate<object> _canExecute;
private Action<object> _method;
public event EventHandler CanExecuteChanged;
public BaseCommand(Action<object> method)
: this(method, null)
{
}
public BaseCommand(Action<object> method, Predicate<object> canExecute)
{
_method = method;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_method.Invoke(parameter);
}
}
}
XAML按钮:
<Button
Name="MyButton"
Command="{Binding MyCommandButton}"
/>
更新
经过更多研究(@RajN示例中的Object parameter
中的MyCommandCanExecuteFunction
每次都返回null
),我偶然发现了以下帖子:object sender is always null in RelayCommand,其中指出我应该使用CommandParameter
,因为它不是null
。
现在,IsValid
函数可以使用,但是即使datagrid
上有错误,也仍会返回TRUE(因此它是有效的)。
我怀疑datagrid /数据本身存在问题,因此我也将其发布在下面:
数据网格
<DataGrid x:Name="MainGrid"
ItemsSource="{Binding ItemList}"
SelectedItem="{Binding SelectedItem,Converter={StaticResource ignoreNewItemPlaceHolderConverter}}"
AutoGenerateColumns="False"
DataContextChanged="OnMainGridDataContextChanged"
CanUserAddRows="False"
>
<DataGrid.Columns>
<DataGridTextColumn>
<DataGridTextColumn.Header>
<Grid Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
</Grid.ColumnDefinitions>
<Button
Height="25"
Width="25"
Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
Command="{Binding Path=DataContext.AddRowCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
ToolTip="Voeg regel toe"
>
<materialDesign:PackIcon
Kind="Add"
Height="24"
Width="24" />
</Button>
</Grid>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding SequenceNumber}"
Header="Line"
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"
Width="63"
IsReadOnly="true" />
<DataGridTextColumn Header="Width" Width="100" IsReadOnly="false" EditingElementStyle="{StaticResource errTemplate}" >
<DataGridTextColumn.Binding>
<Binding Path="Width" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<validationbinding1:RequiredRule ValidatesOnTargetUpdated="True"/>
<validationbinding1:NumericRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
<DataGridTextColumn Header="Height" Width="100" IsReadOnly="false" EditingElementStyle="{StaticResource errTemplate}" >
<DataGridTextColumn.Binding>
<Binding Path="Height" ValidatesOnDataErrors="True" NotifyOnValidationError = "True">
<Binding.ValidationRules>
<validationbinding1:RequiredRule />
<validationbinding1:NumericRule />
</Binding.ValidationRules>
</Binding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
~~Some other columns which are left out
</DataGrid.Columns>
</DataGrid>
DataGrid属性和绑定:
在视图本身上
private void OnMainGridDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
m_MyViewModel = (m_MyViewModel)this.DataContext;
}
在ViewModel中
public class MyViewModel : MyModel
{
// Property variables
private ObservableCollection<ItemListDetails> p_ItemList;
public ICommand MyCommandButton { get; set; }
public MyViewModel()
{
MyCommandButton = new BaseCommand(MyCommandFunction, canExecute);
this.Initialize();
}
private bool canExecute (object obj)
{
return IsValid(obj as DependencyObject);
}
private bool IsValid(DependencyObject obj)
{
// The dependency object is valid if it has no errors and all
// of its children (that are dependency objects) are error-free.
if (obj == null)
return true;
return !Validation.GetHasError(obj) &&
LogicalTreeHelper.GetChildren(obj)
.OfType<DependencyObject>()
.All(IsValid);
}
private void MyCommandFunction(object obj)
{
//... some (not yet implemented) logic
}
private void AddRow(object obj)
{
ItemListDetails Item = new ItemListDetails
{
Width = 0,
Height = 0,
};
p_ItemList.Add(Item);
}
public ObservableCollection<ItemListDetails> ItemList
{
get { return p_ItemList; }
set
{
p_ItemList = value;
this.MutateVerbose(ref p_ItemList, value, RaisePropertyChanged());
}
}
/// <summary>
/// The currently-selected item.
/// </summary>
public ItemListDetails SelectedItem { get; set; }
/// <summary>
/// Updates the ItemCount Property when the list collection changes.
/// </summary>
void OnListChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// Update item count
this.ItemCount = this.p_ItemList.Count;
// Resequence list
SequencingService.SetCollectionSequence(this.p_ItemList);
}
/// <summary>
/// Initializes this application.
/// </summary>
private void Initialize()
{
// Create item list
p_ItemList = new ObservableCollection<ItemListDetails>();
// Subscribe to CollectionChanged event
p_ItemList.CollectionChanged += OnListChanged;
// Initialize list index
this.p_ItemList = SequencingService.SetCollectionSequence(this.p_ItemList);
// Update bindings
//base.RaisePropertyChangedEvent("GroceryList");
//this.MutateVerbose(ref _materiaal, value, RaisePropertyChanged());
}
}
DataGrid项目的ItemListDetails类
public class ItemListDetails : ObservableObject, ISequencedObject
{
// Property variables
private int p_SequenceNumber;
private int p_Width;
private int p_Height;
/// <summary>
/// Default constructor
/// </summary>
public ItemListDetails ()
{
}
/// <summary>
/// Paramterized constructor.
/// </summary>
public ItemListDetails (int width, int height, int itemIndex)
{
p_Width = width;
p_Height = height;
p_SequenceNumber = itemIndex;
}
/// <summary>
/// The sequential position of this item in a list of items.
/// </summary>
public int SequenceNumber
{
get { return p_SequenceNumber; }
set
{
p_SequenceNumber = value;
base.RaisePropertyChangedEvent("SequenceNumber");
}
}
/// <summary>
/// The width
/// </summary>
public int Width
{
get { return p_Width; }
set
{
p_Width = value;
base.RaisePropertyChangedEvent("Int");
}
}
/// <summary>
/// The height
/// </summary>
public int Height
{
get { return p_Height; }
set
{
p_Height = value;
base.RaisePropertyChangedEvent("Int");
}
}
}
MyModel
类包含DataGrid
中未包含的其他一些字段。
答案 0 :(得分:0)
你在这里
public class MyViewModel
{
public ICommand MyCommandButton { get; set; }
public MyViewModel()
{
MyCommandButton = new BaseCommand(MyCommandFunction, MyCommandCanExecuteFunction);
this.Initialize();
}
private void MyCommandFunction(object obj)
{
//... some (not yet implemented) logic
}
private bool MyCommandCanExecuteFunction(object obj)
{
return IsValid(obj as DependencyObject);
}
private bool IsValid(DependencyObject obj)
{
// The dependency object is valid if it has no errors and all
// of its children (that are dependency objects) are error-free.
return !Validation.GetHasError(obj) &&
LogicalTreeHelper.GetChildren(obj)
.OfType<DependencyObject>()
.All(IsValid);
}
}