0

我有一个嵌套的数据网格,其中我有绑定到 RelayCommands 的 + 和 - 按钮,它们分别添加新行或删除当前行。如果只有一个项目留在其类别中,减号按钮命令的 CanExecute 逻辑应该禁用当前行的减号按钮。

问题在于,由于其模板性质,它禁用了所有类别中的所有减号按钮。

图片

如何减轻这种情况?

这是代码。

XAML

 <Grid>
        <DataGrid x:Name="dataGrid1" 
                  ItemsSource="{Binding DataCollection}"
                  SelectedItem="{Binding dataCollectionSelectedItem, Mode=TwoWay}"
                  AutoGenerateColumns="False" 
                  CanUserAddRows="false" >
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Item/Price" Width="*">
                    <DataGridTemplateColumn.CellTemplate >
                        <DataTemplate>
                            <DataGrid x:Name="dataGridItem" 
                                      ItemsSource="{Binding Items}"
                                      SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.itemsSelectedItem, Mode=TwoWay}"
                                      Background="Transparent"
                                      HeadersVisibility="None"
                                      AutoGenerateColumns="False"
                                      CanUserAddRows="false" >
                                <DataGrid.Columns>
                                    <DataGridTextColumn Binding="{Binding Name}" Width="*"/>
                                    <DataGridTextColumn Binding="{Binding Price}" Width="50"/>
                                    <DataGridTemplateColumn Header="Button">
                                        <DataGridTemplateColumn.CellTemplate>
                                            <DataTemplate>
                                                <StackPanel Orientation="Horizontal">
                                                    <Button  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.AddItem }" Width="20" Height="20">+</Button>
                                                    <Button  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.DeleteItem }" Width="20" Height="20">-</Button>
                                                </StackPanel>
                                            </DataTemplate>
                                        </DataGridTemplateColumn.CellTemplate>
                                    </DataGridTemplateColumn>
                                </DataGrid.Columns>
                            </DataGrid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="Category" Binding="{Binding Category}" Width="Auto"/>
                <DataGridTemplateColumn Header="Buttons">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Button  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.AddCategory}" Width="20" Height="20">+</Button>
                                <Button  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.DeleteCategory}" Width="20" Height="20">-</Button>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

C#

 public class Item
    {
        public string Name { get; set; }
        public int Price { get; set; }
    }

    public class DataTable
    {
        public ObservableCollection<Item> Items { get; set; }
        public string Category { get; set; }
    }

    public class RelayCommand : ICommand
    {
        private Action<object> executeDelegate;
        readonly Predicate<object> canExecuteDelegate;

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new NullReferenceException("execute");
            executeDelegate = execute;
            canExecuteDelegate = canExecute;
        }

        public RelayCommand(Action<object> execute) : this(execute, null) { }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return canExecuteDelegate == null ? true : canExecuteDelegate(parameter);
        }

        public void Execute(object parameter)
        {
            executeDelegate.Invoke(parameter);
        }
    }

    public class ViewModel
    {
        public ObservableCollection<DataTable> DataCollection { get; set; }

        public DataTable dataCollectionSelectedItem { get; set; }
        public Item itemsSelectedItem { get; set; }

        public RelayCommand DeleteCategory { get; private set; }
        public RelayCommand AddCategory { get; private set; }
        public RelayCommand DeleteItem { get; private set; }
        public RelayCommand AddItem { get; private set; }

        public ViewModel()
        {
            DataCollection = new ObservableCollection<DataTable>
            {
                new DataTable() {
                    Items = new ObservableCollection<Item> {
                        new Item { Name = "Phone", Price = 220 },
                        new Item { Name = "Tablet", Price = 350 },
                    },
                    Category = "Electronic gadgets" },
                new DataTable() {
                    Items = new ObservableCollection<Item> {
                        new Item { Name = "Teddy Bear Deluxe", Price = 2200 },
                        new Item { Name = "Pokemon", Price = 100 },
                    },
                Category = "Toys" }
            };

            DeleteItem = new RelayCommand(innerDeleteItem, canUseDeleteItem);
            AddItem = new RelayCommand(innerAddItem, canUseAddItem);
        }

        public void innerDeleteItem(object parameter)
        {
            var collectionIndex = DataCollection.IndexOf(dataCollectionSelectedItem);
            if (DataCollection[collectionIndex].Items.Count != 1)
            {
                DataCollection[collectionIndex].Items.Remove(itemsSelectedItem);
                CollectionViewSource.GetDefaultView(DataCollection).Refresh();
            }

        }
        public bool canUseDeleteItem(object parameter)
        {
            var collectionIndex = DataCollection.IndexOf(dataCollectionSelectedItem);
            if ((dataCollectionSelectedItem != null) && (DataCollection[collectionIndex].Items.Count == 1))
            {
                return false;
            }
            else return true;
        }
        public void innerAddItem(object parameter)
        {
            var collectionIndex = DataCollection.IndexOf(dataCollectionSelectedItem);
            var itemIndex = DataCollection[collectionIndex].Items.IndexOf(itemsSelectedItem);
            Item newItem = new Item() { Name = "Item_Name", Price = 0 };
            DataCollection[collectionIndex].Items.Insert(itemIndex + 1, newItem);
            CollectionViewSource.GetDefaultView(DataCollection).Refresh();
        }
        public bool canUseAddItem(object parameter)
        {
            return true;
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            ViewModel newViewModel = new ViewModel();
            this.DataContext = newViewModel;
        }
    }
4

2 回答 2

0

您将两个命令绑定到 Window 的数据上下文,它应该绑定到 DataGrid 的数据上下文。

将您的 xaml 更改为:

<StackPanel Orientation="Horizontal">
     <Button  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.AddItem }" Width="20" Height="20">+</Button>
     <Button  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.DeleteItem }" Width="20" Height="20">-</Button>
</StackPanel>
于 2017-03-24T00:48:20.567 回答
0

我最终将按钮的 CanExecute 设置为始终返回 true 并使用自定义触发器设置按钮的样式,当 Items.Count 变为 1 时将其禁用。也许有更优雅的解决方案,但至少这个对我有用。

<Button  Content="-"
         Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.DeleteItem }"
         Width="20" Height="20">
     <Button.Style>
         <Style TargetType="Button">
             <Setter Property="IsEnabled" Value="True" />
             <Style.Triggers>
                 <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=Items.Count }" Value="1">
                     <Setter Property="IsEnabled" Value="False" />
                 </DataTrigger>
              </Style.Triggers>
         </Style>
     </Button.Style>
</Button>
于 2017-03-24T15:13:52.043 回答