WPF- datagrid行验证错误到文本块/标签?

时间:2015-06-30 07:00:11

标签: c# wpf validation xaml datagrid

在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

2 个答案:

答案 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.TextTextBlock.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