WPF DataGrid 文件名列允许直接文本输入或按钮通过对话框浏览

问题描述 投票:0回答:1

我有一个带有 DataGrid 的 WPF 应用程序,用户将在其中输入文件名。我希望他们能够通过双击直接输入文件名,或者单击“浏览”按钮启动打开的文件对话框。

这是 XAML:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="450" Width="800">
    <DataGrid Name="TheDataGrid" 
              ItemsSource="{Binding Inputs}" 
              AutoGenerateColumns="False" 
              CanUserAddRows="True">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Filename" Width="*">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <DockPanel>
                            <Button DockPanel.Dock="Right" Content="Browse" Click="BrowseButton_Click" />
                            <TextBlock Text="{Binding Filename}" />
                        </DockPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <DockPanel>
                            <Button DockPanel.Dock="Right" Content="Browse" Click="BrowseButton_Click" />
                            <TextBox Text="{Binding Filename}" />
                        </DockPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Window>

这是代码:

public partial class MainWindow : Window
{
    public ObservableCollection<Input> Inputs { get; set; } = new ObservableCollection<Input>();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog ofd = new OpenFileDialog();
        if (!ofd.ShowDialog().Value)
            return;
        if (((Button)sender).DataContext is Input i)
            i.Filename = ofd.FileName;
        else
        {
            // what to do here?
        }
    }
}

public class Input : INotifyPropertyChanged
{
    private string filename;

    public string Filename
    {
        get { return filename; }
        set
        {
            filename = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Filename"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

我的问题是:

  1. 当用户单击新行上的“浏览”按钮时,
    DataContext
    不是类型
    Input
    ,而是
    DataGrid.NewItemPlaceholder
    ,所以我没有什么可设置文件名的。我尝试直接修改
    TextBlock
    Text
    ,这有效,但即使手动发出该命令,它也不会提交新行。
  2. 当用户双击手动输入文件名时,它会进入编辑模式,但似乎需要再单击一次才能真正接受输入。有没有办法避免这种情况,并使行为更像
    DataGridTextColumn
c# .net wpf datagrid
1个回答
0
投票

但问题 #1 是迄今为止更紧迫的问题,是的,它只发生在新行中。

也许有更简单的方法,但从多次尝试实现来看,到目前为止我只成功了这个选项:

            <DataGridTemplateColumn Header="Filename" Width="*">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <DockPanel>
                            <Button DockPanel.Dock="Right" Content="Browse"
                                    Click="BrowseButton_Click"
                                    CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridCell}}"
                                    Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>
                            <TextBlock x:Name="tb" Text="{Binding Filename}" />
                        </DockPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <DockPanel>
                            <Button x:Name="btn" DockPanel.Dock="Right" Content="Browse"
                                    Click="BrowseButton_Click"
                                    CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridCell}}"/>
                            <TextBox Name="tb" Text="{Binding Filename}" />
                        </DockPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
        private static object NewItemPlaceholder = typeof(DataGrid)?
            .GetProperty("NewItemPlaceholder", BindingFlags.Static | BindingFlags.NonPublic)?
            .GetValue(null)!;

        private void BrowseButton_Click(object sender, RoutedEventArgs e)
        {
            Button button = (Button)sender;
            FrameworkElement cp = (FrameworkElement)button.CommandParameter;
            object dc = button.DataContext;
            ItemsControl ic = (ItemsControl)button.Tag;

            if (dc == NewItemPlaceholder)
            {
                DataGridCell cell = (DataGridCell)cp; ;
                DataGridRow row = DataGridRow.GetRowContainingElement(cell);
                int rowindex = row.GetIndex();
                DataGrid.BeginEditCommand.Execute(null, cell);

                DataGridRow newrow = (DataGridRow)ic.ItemContainerGenerator.ContainerFromIndex(rowindex);
                dc = newrow.DataContext;
            }


            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == true)
            {
                if (dc is Input i)
                {
                    i.Filename = ofd.FileName;
                }
                else
                {
                    throw new Exception("Something went wrong...");
                }
            }
        }
© www.soinside.com 2019 - 2024. All rights reserved.