简体   繁体   中英

WPF Datagrid ValidationRules on ItemsSource

I want to put a red-border around a DataGrid when it has no rows (Im doing the binding to ItemsSource).

So i was following this guide for WPF Validation:

http://www.codeproject.com/Articles/15239/Validation-in-Windows-Presentation-Foundation

Anyhow, it is simple enough to make a textbox have such an error when the Text = "" :

空文本框错误

and even customize the error:

绿色

I tried debugging and the ValidationRules that are bound within my ItemsSource are never invoked.

<DataGrid ...>
 <DataGrid.ItemsSource>
   <Binding Path="Lines" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
       <Binding.ValidationRules>
         <DataGridValidationRule
               MiniumRows="1"
               MaximumRows="100"
               ErrorMessage="must have between 1 and 100 rows">
         </DataGridValidationRule>
       </Binding.ValidationRules>
     </Binding>
 </DataGrid.ItemsSource>
</DataGrid>

And then the DataGridValidtionRule class looks like this:

public class  public class StringRangeValidationRule : ValidationRule
{
    private int _minimumRows = -1;
    private int _maximumRows = -1;
    private string _errorMessage;

    public int MinimumRows
    {
        get { return _minimumRows ; }
        set { _minimumRows  = value; }
    }

    public int MaximumRows
    {
        get { return _maximumLength; }
        set { _maximumLength = value; }
    }

    public string ErrorMessage
    {
        get { return _errorMessage; }
        set { _errorMessage = value; }
    }

    public override ValidationResult Validate(object value, 
        CultureInfo cultureInfo)
    {
        ValidationResult result = new ValidationResult(true, null);
        ObservableCollection<Lines> lines = (ObservableCollection<Lines>) value;
        if (lines.Count < this.MinimumRows||
               (this.MaximumRows> 0 &&
                lines.Count > this.MaximumRows))
        {
            result = new ValidationResult(false, this.ErrorMessage);
        }
        return result;
    }

And the "Lines" class

 public class Line
  {
    public Line(string f, string b)
    {
      foo = f;
      bar = b;
    }
   public string Foo {get; set;}
   public string Bar {get; set;}
  }

EDIT:

It turns out that my "delete row" button for my datagrid was removing from the ObservableCollection but not through the actual DataGrid (it was removing at the ViewModel)... and for some reason this prevents the Validation call from being invoked.

So again the View:

<DataGrid Name="mygrid">
 <DataGrid.ItemsSource>
   <Binding Path="Lines" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
       <Binding.ValidationRules>
         <DataGridValidationRule
               MiniumRows="1"
               MaximumRows="100"
               ErrorMessage="must have between 1 and 100 rows">
         </DataGridValidationRule>
       </Binding.ValidationRules>
     </Binding>
 </DataGrid.ItemsSource>
</DataGrid>

so if i had in the ViewModel:

void delete(Line l)
{
  Lines.Remove(l); //if you delete everything (grid empty) there won't be any error shown.
}

The error border & icon wouldn't show up around the datagrid.

But if instead i put a event that directly changed the ItemsSource like this:

 void delete(Line l)
    {
      Lines.Remove(l);
      myView.mygrid.ItemsSource = Lines; // this magically fixes everything... even though it was already bound to Lines... though i hate to directly access the View from within the ViewModel.
    }

I'm not sure why exactly... but that fixed it. Any ideas on how i could separate the view from the VM? I don't really like this fix.

Try to put the datagrid in a border and attach a trigger to it to make it red once datagrid is empty

<Border Margin="20" >
    <Border.Style>
        <Style TargetType="Border">
            <Style.Triggers>
                <DataTrigger  Binding="{Binding ISEmpty}" Value="True">
                    <Setter Property="BorderThickness" Value="2" />
                    <Setter Property="BorderBrush" Value="Red" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Border.Style>
    <DataGrid  Name="myGrid" AutoGenerateColumns="True"  ItemsSource="{Binding Path=Lecturers}" >

    </DataGrid>
</Border>

Set IsEmpty property to true when you clear the grid

private bool iSEmpty;

public bool ISEmpty
{
    get { return iSEmpty; }
    set
    {
        iSEmpty = value;
        NotifyPropertyChanged("ISEmpty");
    }
}

Clear your item source collection

viewmodel.Lecturers.Clear();
this.viewmodel.ISEmpty = true;

Future work. You can bind trigger to datagrid control.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM