MVVM WPF:验证autogeneratedcolumns的datagrid行

时间:2014-07-14 11:41:13

标签: c# wpf mvvm datagrid

我正在创建一个DataTable,其列存储在列表中。

public class CustomColumn
{
    public string ColumnName { get; set; }
    public int MinLength { get; set; }
    public int MaxLength { get; set; }
}

public class ViewModel
{
    public List<CustomColumn> Columns { get; set; }
    public DataTable MyTable { get; set; }

    public ViewModel()
    {
        InitializeCustomColumns();
        MyTable = new DataTable();

        foreach (CustomColumn column in Columns)
        {
            MyTable.Columns.Add(column.ColumnName, typeof(string));
        }
    }
}

现在我将DataTable绑定到DataGrid并允许用户在DataGrid中添加行。在运行时初始化列列表时,将自动生成我的DataGrid列。当用户在行的特定列中输入某个值时,我想基于CustomColumn属性 - &gt;进行验证。 MinLength(最小字符串长度)&amp; MaxLength(允许的最大字符串长度)。如果验证失败,我想显示DataGrid中出现的默认红色边框,表示无效输入。我正在关注MVVM软件架构模式。

修改

我附上ColumnChanging听众

MyTable.ColumnChanging += tableColumnChanging;

private void tableColumnChanging(object sender, DataColumnChangeEventArgs e)
{
    //I am able to validate here using my logic
    if(!isValid(e))
    {
        object badValue = e.ProposedValue;
        e.ProposedValue = "Bad Data";
        e.Row.RowError = "The column contains an error";
        e.Row.SetColumnError(e.Column, "Column cannot be " + badValue);
    }
    else
    {
        ... 
    }

}

我能够验证,但我想显示我的单元格!标记如果isValid返回false。

1 个答案:

答案 0 :(得分:1)

我设法为同一个

做了一个解决方法

XAML

<ScrollViewer xmlns:l="clr-namespace:CSharpWPF">
    <ScrollViewer.Resources>
        <DataTemplate DataType="{x:Type l:CustomTable}">
            <DataTemplate.Resources>
                <l:ErrorToVisibilityConverter x:Key="ErrorToVisibilityConverter" />
                <Style TargetType="DataGridCell">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="DataGridCell">
                                <Grid Background="{TemplateBinding Background}">
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text=" ! "
                                                   FontWeight="Bold"
                                                   Foreground="Red">
                                            <TextBlock.Visibility>
                                                <MultiBinding Converter="{StaticResource ErrorToVisibilityConverter}"
                                                              Mode="OneWay">
                                                    <Binding RelativeSource="{RelativeSource FindAncestor,AncestorType=DataGridCell}" />
                                                    <Binding Path="Tag.Errors"
                                                             RelativeSource="{RelativeSource FindAncestor,AncestorType=DataGrid}" />
                                                    <Binding />
                                                </MultiBinding>
                                            </TextBlock.Visibility>
                                        </TextBlock>
                                        <ContentPresenter />
                                    </StackPanel>
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataTemplate.Resources>
            <StackPanel>
                ...
            </StackPanel>
        </DataTemplate>
    </ScrollViewer.Resources>
    <ContentControl Content="{Binding TableCollection}" />
</ScrollViewer>

我为Style添加了DataGridCell,并使用我们的额外元素定义了自定义Template以显示!标记

转换器类

namespace CSharpWPF
{
    public class ErrorToVisibilityConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            DataGridColumn column = values[0] as DataGridColumn;
            ObservableCollection<DataColumnChangeEventArgs> errors = values[1] as ObservableCollection<DataColumnChangeEventArgs>;
            DataRowView view = values[2] as DataRowView;

            DataColumnChangeEventArgs args = errors.FirstOrDefault(e => (e.Row == view.Row) && (e.Column.Ordinal == column.DisplayIndex));

            return view.Row.HasErrors && args != null ? Visibility.Visible : Visibility.Collapsed;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

这将检测当前单元格是受影响的单元格,如果为真,则返回Visibility.Visible否则Visibility.Collapsed因此隐藏或显示额外元素,具体取决于错误状态

更改CustomTable

public CustomTable()
{
    ...

    Errors = new ObservableCollection<DataColumnChangeEventArgs>();
}

private void tableColumnChanging(object sender, DataColumnChangeEventArgs e)
{
    if (!isValid(e))
    {
        object badValue = e.ProposedValue;
        e.ProposedValue = "Bad Data";
        e.Row.RowError = "The column contains an error";
        e.Row.SetColumnError(e.Column, "Column cannot be " + badValue);
        Errors.Add(e);
        OnPropertyChanged("Errors");
    }
    else
    {
        DataColumnChangeEventArgs args = Errors.FirstOrDefault(ee => (ee.Row == e.Row) && (ee.Column == e.Column));
        if (args != null)
        {
            Errors.Remove(args);
            OnPropertyChanged("Errors");
        }
        //... 
    }
}

public ObservableCollection<DataColumnChangeEventArgs> Errors { get; set; }

结果

result

所以整个想法是添加一个带有通知更改功能的额外属性,并将其用作触发器和其他属性来检测相应的列,而rest是我们额外的可见性!自定义模板中的元素