Проверка строк сетки при нажатии кнопки с помощью пользовательской реализации ICommand - WPF - PullRequest
0 голосов
/ 24 декабря 2018

Я хочу проверить мои DataGrid строки на наличие ошибок, и если есть какие-либо ошибки, то кнопка «Сохранить» должна быть отключена или, по крайней мере, должно быть какое-то сообщение о том, что есть ошибки.

После некоторых исследований я наткнулся на следующий пост: Обнаружение ошибок валидации WPF

В посте есть решение использовать этот фрагмент кода для проверки 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}"
/>

ОБНОВЛЕНИЕ

После еще одного исследования (Object parameter из MyCommandCanExecuteFunction в примере @RajN возвращало null каждый раз) я наткнулся на следующий пост: отправитель объекта всегда равен нулю в RelayCommand , в котором говорится, что яследует использовать CommandParameter, чтобы оно не было null.Теперь функция IsValid работает, но продолжает возвращать TRUE (поэтому она действительна), даже если в datagrid.

есть подозрения, что я подозреваю, что с самой сеткой данных / данными что-то не так, поэтому я опубликуюа также ниже:

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());

    }

}

Класс ItemListDetails элементов DataGrid

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.

1 Ответ

0 голосов
/ 24 декабря 2018

Вот, пожалуйста,

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);
    }
}
...