Why are the datagrid delete command buttons disabl

2019-06-10 07:56发布

问题:

I have a DataGrid where each row has a delete button. If I set the Command="Delete" attribute on the Delete button element in XAML, the button is disabled at runtime. Why??

XAML:

<Page x:Class="AxureExport.TargetPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:local="clr-namespace:AxureExport"
  mc:Ignorable="d" 
  d:DesignHeight="300" d:DesignWidth="400"
  Title="Define Export Targets"
  Loaded="Page_Loaded">

<Page.Resources>
    <Style TargetType="{x:Type DataGridCell}">
        <EventSetter Event="PreviewMouseLeftButtonDown"
                     Handler="DataGridCell_PreviewMouseLeftButtonDown" />
    </Style>
</Page.Resources>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="7" />
        <ColumnDefinition Width="65" />
        <ColumnDefinition Width="458*" />
        <ColumnDefinition Width="47" />
        <ColumnDefinition Width="10" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="7" />
        <RowDefinition Height="63*" />
    </Grid.RowDefinitions>
    <!-- target file -->
    <TextBlock Name="textBlock3"
               Text="2. Select the location where you want to save the string files:"
               Height="23"
               HorizontalAlignment="Left"
               Margin="5,0,0,0"
               VerticalAlignment="Top"
               Grid.Row="2"
               Grid.Column="1"
               Grid.ColumnSpan="4"
               Width="441" />
    <TextBlock Name="textBlock4"
               Text="(Warning: This tool overwrites files in the target folder.)"
               Height="16"
               HorizontalAlignment="Left"
               Margin="54,15,0,0"
               VerticalAlignment="Top"
               Width="256"
               FontStyle="Italic"
               FontWeight="Light"
               FontSize="10"
               Grid.Row="2"
               Grid.Column="1"
               Grid.ColumnSpan="2" />
    <TextBlock Name="textBlock5"
               Text="Target:"
               Height="23"
               HorizontalAlignment="Left"
               Margin="22,30,0,238"
               VerticalAlignment="Center"
               Grid.Row="1"
               Grid.Column="1" />
    <!-- ExportTargets Datagrid -->
    <DataGrid Name="ExportTargets"
              AutoGenerateColumns="False"
              Grid.Column="2"
              Grid.Row="1"
              Margin="0,71,0,63"
              ItemsSource="{Binding Path=., Mode=TwoWay}"
              SelectionUnit="Cell"
              GridLinesVisibility="None"
              RowDetailsVisibilityMode="Collapsed"
              CanUserReorderColumns="False"
              CanUserResizeColumns="False"
              CanUserResizeRows="False"
              RowHeaderWidth="40"
              IsSynchronizedWithCurrentItem="True"
              HorizontalScrollBarVisibility="Disabled"
              CanUserAddRows="True"
              CanUserDeleteRows="True">
        <DataGrid.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                             Color="Transparent" />
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
                             Color="Transparent" />
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}"
                             Color="Black" />
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}"
                             Color="Black" />
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Binding="{Binding IsXML, Mode=TwoWay}"
                                Header="XML"
                                CanUserSort="False"
                                CanUserReorder="False" />
            <DataGridCheckBoxColumn Binding="{Binding IsProperty, Mode=TwoWay}"
                                    Header="Property"
                                    CanUserSort="False"
                                    CanUserReorder="False" />
            <DataGridTextColumn Binding="{Binding FolderName, Mode=TwoWay}"
                                Header="Folder"
                                Width="*"
                                CanUserReorder="False"
                                IsReadOnly="False" />
            <DataGridTemplateColumn Header="Browse">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button Name="Browse"
                                Command="{Binding BrowseCommand}"
                                HorizontalAlignment="Center"
                                Width="20">...</Button>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Delete" IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button Name="Delete"
                                Command="{x:Static DataGrid.DeleteCommand}"
                                HorizontalAlignment="Center"
                                Width="20"
                                IsEnabled="True">X</Button>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
    <Button Name="NextButton"
            Content="Next"
            Grid.Column="2"
            Grid.ColumnSpan="2"
            Grid.Row="1"
            Margin="0,0,2,12"
            Width="100"
            Height="40"
            HorizontalAlignment="Right"
            VerticalAlignment="Bottom"
            Click="NextButton_Click" />
</Grid>
</Page>

Code-behind:

// DataTable
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace AxureExport {

/// <summary>
/// Interaction logic for TargetPage.xaml
/// </summary>
public partial class TargetPage : Page {

    FrameWindow _frame;
    //ExportTargetInfos _eti;

    public TargetPage(FrameWindow frame) {
        InitializeComponent();

        _frame = frame;
        _frame.ExportTargets = new ExportTargetInfos(Properties.Settings.Default.ExportTargetHistory);
        this.DataContext = _frame.ExportTargets;
    }

    //
    // enable editing on single-click
    private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
        DataGridCell cell = sender as DataGridCell;

        if (!cell.IsEditing) {
            if (!cell.IsFocused)
                cell.Focus();

            if (!cell.IsSelected)
                cell.IsSelected = true;
        }
    }

    private void Page_Loaded(object sender, RoutedEventArgs e) {
    }

    private void NextButton_Click(object sender, RoutedEventArgs e) {
        Properties.Settings.Default.ExportTargetHistory = _frame.ExportTargets.GetExportTargets();
        _frame.NavigateTo(typeof(ExportPage));
    }
}
}

ViewModel:

using System;
using System.Collections.ObjectModel;       // ObservibleCollection<>
using System.Collections.Specialized;       // StringCollection
using System.ComponentModel;                // INotifyPropertyChanged

namespace AxureExport {
public class ExportTargetInfos : ObservableCollection<ExportTargetInfo> {

    const char _SEP = '|';      // field seperator character

    // default constructor
    public ExportTargetInfos() : base() {
    }

    // copy constructors
    public ExportTargetInfos(ExportTargetInfos etis) : base() {
        if (etis == null) return;
        foreach (ExportTargetInfo eti in etis) {
            this.Add(new ExportTargetInfo(eti.FolderName, eti.IsXML, eti.IsProperty));
        }
    }

    public ExportTargetInfos(StringCollection sc) : base() {
        if (sc == null) return;
        foreach (string s in sc)
            Add(ParseExportTarget(s));
    }

    public StringCollection GetExportTargets() {
        StringCollection sc = new StringCollection();

        foreach (ExportTargetInfo et in this)
            sc.Add(BuildExportTarget(et));

        return sc;
    }

    // create a string from an ExportTarget (for persistance)
    private static string BuildExportTarget(ExportTargetInfo et) {
        return et.FolderName + _SEP + et.IsXML.ToString() + _SEP + et.IsProperty.ToString();
    }

    // create an ExportTarget from an unparsed string (for persistance)
    private static ExportTargetInfo ParseExportTarget(string s) {
        int count = s.Split(_SEP).Length - 1;
        string[] items = s.Split(new[] { _SEP }, StringSplitOptions.None);
        string name = (count < 1 ? String.Empty : items[0]);
        bool isXML = (count > 0 ? Convert.ToBoolean(items[1]) : false);
        bool isProp = (count > 1 ? Convert.ToBoolean(items[2]) : false);
        return new ExportTargetInfo(name, isXML, isProp);
    }
}

//
// represents an export target (folder plus options) in it's parsed form
public class ExportTargetInfo : INotifyPropertyChanged {

    public event PropertyChangedEventHandler PropertyChanged;

    public IDelegateCommand BrowseCommand { protected set; get; }

    // default constructor is needed to enable datagrid to add rows
    public ExportTargetInfo() {
        _folderName = String.Empty;
        _isXML = false;
        _isProperty = false;
        this.BrowseCommand = new DelegateCommand(ExecuteBrowse, CanExecuteBrowse);
    }

    public ExportTargetInfo(string targetFolderName, bool isXML, bool isProperties) {
        _folderName = targetFolderName;
        _isXML = isXML;
        _isProperty = isProperties;
        this.BrowseCommand = new DelegateCommand(ExecuteBrowse, CanExecuteBrowse);
    }

    private string _folderName;
    public string FolderName {
        get { return _folderName; }
        set { SetProperty<string>(ref _folderName, value, @"FolderName"); }
    }

    private bool _isXML;
    public bool IsXML {
        get { return _isXML; }
        set { SetProperty<bool>(ref _isXML, value, @"IsXML"); }
    }

    private bool _isProperty;
    public bool IsProperty {
        get { return _isProperty; }
        set { SetProperty<bool>(ref _isProperty, value, @"IsProperty"); }
    }

    // browse button for selected row clicked
    void ExecuteBrowse(object param) {
        // use WPF-WinForms interop (:-p)
        var folderDialog = new System.Windows.Forms.FolderBrowserDialog();
        folderDialog.Description = "Please designate the target folder";
        folderDialog.SelectedPath = FolderName;
        folderDialog.ShowNewFolderButton = true;
        if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            FolderName = folderDialog.SelectedPath;
    }

    bool CanExecuteBrowse(object param) {
        return true;
    }

    protected bool SetProperty<T>(ref T storage, T value, string propertyName = null) {
        if (object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged(string propertyName) {
        if (PropertyChanged != null)
            PropertyChanged( this, new PropertyChangedEventArgs(propertyName));
    }
}
}

Does anyone have insight as to what's the cause?

回答1:

This isn't a solution, but through trial & error I discovered the disabled delete button behavior is caused by the SelectionUnit="Cell" setting in the DataGrid. Setting it to FullRow enables the delete row button.



回答2:

<Button Name="NextButton" isEnable = "true" />