在WPF中,我有一个DataDrid
具有不同的验证。
到目前为止,我在ToolTip
中使用DataGrid
来显示错误验证:
<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" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
现在客户端要求在页面中的其他TextBlock/Label
中显示验证错误 - 我该怎么做?如何使用(Validation.Errors)[0].ErrorContent
以外的DataGrid
?
答案 0 :(得分:0)
你可能有一个像ValidationRules这样的类,它包含一个验证函数。
由于发生了宏伟的绑定,您不再需要遵循验证,因为它是绑定的。然而,这坚持控制。
您还可以在数据网格内的控件上创建一个用于验证的事件。
<DataGridTemplateColumn Header="MyValue">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Textbox Text="{Binding MyValue}" OnLeave="tb_OnLeave"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
在你身后,你可以拥有类似的东西:
private void tb_OnLeave(object sender, EventArgs e)
{
//sender defines your value;
Textbox s = (Textbox)sender;
//validate the Text property of the sender
if(ValidationRule.ValidateTextBox(s.Text)); //true
return;
//set the focus on your control
s.Focus();
//set the text of your other control
YourOtherControl.Text = string.Format("The value of textbox: {0} is not valid", s.Text);
}
这里的要点是你不再使用validationBinding了。 我认为有办法通过绑定来做到这一点,但我对这个话题不够强大,无法给你一个更好的答案。
也许 RelativeSource 可用于指向另一个控件。但正如我所说,我不太清楚,不能确定。
答案 1 :(得分:0)
假设您有一个列表(例如MyList
)作为DataGrid.ItemsSource
ObservableCollection<ItemVM>
,其中ItemVM
代表每个DataGridRow
的视图模型您可以使用带有多值转换器的MultiBinding
将最后一条错误消息保存在当前无效ItemVM
的属性中(例如ErrorMessage
),然后在您想要的{{1}中检索它通过绑定。
你可以说这是3-way绑定的一种技巧,其中TextBlock.Text
和TextBlock.Text
以及CurrentItem.ErrorMessage
都绑定在一起。
以下代码将清除:
在MainWindow中:
(Validation.Errors)[0].ErrorContent
在ItemVM中:
public ObservableCollection<ItemVM> MyList { get; set; }
public ItemVM CurrentItem { get; set; }
在Xaml中:
public class ItemVM : INotifyPropertyChanged
{
//implementation of INotifyPropertyChanged ...
string _errorMessage;
public string ErrorMessage
{
get
{
return _errorMessage;
}
set
{
_errorMessage = value;
OnPropertyChanged("ErrorMessage");
}
}
// Other Properties ...
}
最后在MultiValueConverter中:
<Window.Resources>
<local:MultiConverter x:Key="multiConv"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0" ItemsSource="{Binding MyList}" >
<DataGrid.RowValidationErrorTemplate>
<ControlTemplate >
<Grid Margin="0,-2,0,-2">
<Ellipse StrokeThickness="0" Fill="Red" Width="{TemplateBinding FontSize}" Height="{TemplateBinding FontSize}" />
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}" FontWeight="Bold" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Grid.ToolTip>
<MultiBinding Converter="{StaticResource multiConv}">
<Binding Path="(Validation.Errors)[0].ErrorContent" RelativeSource="{RelativeSource Mode=FindAncestor,
AncestorType=DataGridRow}"/>
<Binding Path="DataContext.CurrentItem" RelativeSource="{RelativeSource Mode=FindAncestor,
AncestorType=Window}"/>
</MultiBinding>
</Grid.ToolTip>
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
</DataGrid>
<TextBox Grid.Row="1" Text="{Binding CurrentItem.ErrorMessage}"/>
</Grid>
修改强>
我的DataGrid.ItemsSource是DataSet DefaultView-它的基于数据库的
好的,因为您使用public class MultiConverter : IMultiValueConverter
{
public object Convert(
object[] values, Type targetType, object parameter, CultureInfo culture)
{
((ItemVM)values[1]).ErrorMessage = values[0].ToString();
return values[0].ToString();
}
public object[] ConvertBack(
object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
作为DataSet.DefaultView
这样做:
1)首先定义一个非常小的简单类,它实现ItemsSource
来包装你的错误信息:
INotifyPropertyChanged
2)然后在public class ErrorContainer: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
string _message;
public string Message
{
get
{return _message;}
set
{_message = value; OnPropertyChanged("Message");}
}
}
中使用此类的实例作为属性:
MainWindow
3)现在将多重绑定中的第二条路径更改为public partial class MainWindow : Window
{
....
public ErrorContainer Error { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
// initialize ErrorContainer
Error = new ErrorContainer();
// some dummy test data (you're probably getting your data from DB instead)
DataSet ds = new DataSet("MyDataSet");
DataTable dt = new DataTable("MyDataTable");
DataColumn propertyName = new DataColumn("Property");
DataColumn propertyValue = new DataColumn("Value");
DataColumn propertyDate = new DataColumn("Date", typeof(DateTime));
dt.Columns.Add(propertyName);
dt.Columns.Add(propertyValue);
dt.Columns.Add(propertyDate);
dt.Rows.Add("Name1", 1, DateTime.Now);
dt.Rows.Add("Name2", 2, DateTime.Now);
dt.Rows.Add("Name3", 3, DateTime.Now);
ds.Tables.Add(dt);
// bind DataGrid.ItemsSource (do NOT set this again in xaml)
var srcBinding = new Binding();
srcBinding.Source = ds.Tables[0].DefaultView;
myDataGrid.SetBinding(DataGrid.ItemsSourceProperty, srcBinding);
}
}
,并将DataContext.Error
绑定更改为TextBox.Text
:
Error.Message
4)最后将<Grid>
<DataGrid x:Name=x:Name="myDataGrid">
....
<MultiBinding Converter="{StaticResource multiConv}">
<Binding Path="(Validation.Errors)[0].ErrorContent" RelativeSource="{RelativeSource Mode=FindAncestor,
AncestorType=DataGridRow}"/>
<Binding Path="DataContext.Error" RelativeSource="{RelativeSource Mode=FindAncestor,
AncestorType=Window}"/>
</MultiBinding>
</Grid.ToolTip>
</Grid>
</ControlTemplate>
</DataGrid.RowValidationErrorTemplate>
</DataGrid>
<TextBox Grid.Row="1" Text="{Binding Error.Message}"/>
</Grid>
方法更改为:
MultiValueConverter.Convert