DataGridTemplateColumn中的ComboBox未调整大小

时间:2017-08-09 10:16:00

标签: c# wpf combobox datagrid

问题简介

我的DataGridDataGridTemplateColumn,其模板包含ComboBox控件。我的问题是,当所选项目的显示成员太长而无法适应ComboBox的宽度时,ComboBox的宽度不会扩展以适应所显示的内容的宽度,如果同一ComboBox不在DataGrid

工作示例

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="350" Width="525">
   <StackPanel>
      <DataGrid Height="150"
                Margin="0,4,0,0"
                CanUserAddRows="False"
                CanUserDeleteRows="False"
                CanUserReorderColumns="False"
                CanUserResizeColumns="False"
                HorizontalAlignment="Stretch"
                ColumnWidth="SizeToCells"
                HeadersVisibility="Column"
                AutoGenerateColumns="False"
                RowHeaderWidth="0"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding Path=Entities, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
                SelectedItem="{Binding Path=SelectedEntity}"
                SelectionUnit="FullRow"
                SelectionMode="Single">
         <DataGrid.Resources>
            <DataTemplate x:Key="TextBox_Template">
               <TextBox Text="{Binding Path=Text}" Margin="2,2,2,2"/>
            </DataTemplate>
            <DataTemplate x:Key="ComboBox_Template">
               <ComboBox Margin="2,2,2,2"
                         Width="Auto"
                         ItemsSource="{Binding Path=DataContext.AvailableActions,
                                               Mode=OneTime,
                                               RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                         SelectedValue="{Binding Path=Action, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                         SelectedValuePath="Key"
                         DisplayMemberPath="Value"
                         IsEditable="False"
                         IsSynchronizedWithCurrentItem="False"/>
            </DataTemplate>
         </DataGrid.Resources>
         <DataGrid.Columns>
            <DataGridTemplateColumn Width="*"
                                    CanUserReorder="False" CanUserResize="False"
                                    CellTemplate="{StaticResource TextBox_Template}"
                                    Header="Text Field"/>
            <DataGridTemplateColumn Width="Auto"
                                    CanUserReorder="False" CanUserResize="False"
                                    CellTemplate="{StaticResource ComboBox_Template}"
                                    Header="Action"/>
         </DataGrid.Columns>
      </DataGrid>
      <Separator Margin="0,5,0,5"/>
      <StackPanel Orientation="Horizontal">
         <Button Content="Add Row" Margin="2,2,2,2"
                 Command="{Binding AddRowCommand}"/>
         <Button Content="Remove Row" Margin="2,2,2,2"
                 Command="{Binding RemoveRowCommand}"/>
      </StackPanel>
      <Separator Margin="0,5,0,5"/>
      <ComboBox Width="Auto"
                ItemsSource="{Binding Path=AvailableActions}"
                SelectedValuePath="Key"
                DisplayMemberPath="Value"
                IsEditable="False"
                HorizontalAlignment="Left"/>
   </StackPanel>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace WpfApplication1
{
   /// <summary>
   /// Interaction logic for MainWindow.xaml
   /// </summary>
   public partial class MainWindow : Window, INotifyPropertyChanged
   {
      public event PropertyChangedEventHandler PropertyChanged;

      public static Dictionary<ActionType, string> AvailableActions { get; set; }

      public EntityClass SelectedEntity { get; set; }

      public ObservableCollection<EntityClass> Entities { get; set; }

      public AddRowCommandClass AddRowCommand { get; set; }

      public RemoveRowCommandClass RemoveRowCommand { get; set; }

      static MainWindow()
      {
         AvailableActions = new Dictionary<ActionType, string>()
         {
            {ActionType.Accept,   "Accept the text"},
            {ActionType.Reject,   "Reject the text"},
            {ActionType.Refer,    "Refer the text"},
            {ActionType.Postpone, "Postpone the text"},
         };
      }

      public MainWindow()
      {
         Entities = new ObservableCollection<EntityClass>()
         {
            new EntityClass() { Text = "First Example Text",  Action = ActionType.Accept},
            new EntityClass() { Text = "Second Example Text", Action = ActionType.Reject},
            new EntityClass() { Text = "Third Example Text",  Action = ActionType.Refer},
         };
         AddRowCommand = new AddRowCommandClass(this);
         RemoveRowCommand = new RemoveRowCommandClass(this);

         InitializeComponent();
      }

      public enum ActionType
      {
         Accept,
         Reject,
         Refer,
         Postpone,
      }

      public class EntityClass
      {
         public string Text { get; set; }
         public ActionType Action { get; set; }
      }

      public class AddRowCommandClass : ICommand
      {
         public event EventHandler CanExecuteChanged;
         private MainWindow _window;

         public AddRowCommandClass(MainWindow window)
         {
            _window = window;
         }

         public bool CanExecute(object parameter)
         {
            return true;
         }

         public void Execute(object parameter)
         {
            _window.Entities.Add(new EntityClass() { Text = "Hello World!", Action = ActionType.Postpone });
         }
      }

      public class RemoveRowCommandClass : ICommand
      {
         public event EventHandler CanExecuteChanged;
         private MainWindow _window;

         public RemoveRowCommandClass(MainWindow window)
         {
            _window = window;
         }

         public bool CanExecute(object parameter)
         {
            return _window.SelectedEntity != null;
         }

         public void Execute(object parameter)
         {
            _window.Entities.Remove(_window.SelectedEntity);
            _window.SelectedEntity = null;
            _window.PropertyChanged?.Invoke(_window, new PropertyChangedEventArgs("SelectedEntity"));
         }
      }
   }
}

重现的步骤

  • 首先观察页面底部的ComboBox会随着所选值的大小发生变化而改变大小。
  • 接下来向DataGrid添加新行或编辑已存在的行中的ComboBox以选择"Postpone the text"选项;注意ComboBox如何更改大小以适应较大的文本,导致文本被剪裁。
  • 最后将窗口调整为更大的尺寸,其中一行选择了"Postpone the text",并注意ComboBox现在如何增加宽度以适应较长的文本而不剪裁。

结论/问题

我的问题是如何强制ComboBox控件自动适应所选项目的宽度,并在必要时增加网格行的宽度。我希望它能够永远不会剪切所选文本,即使这意味着修改DataGrid中特定列的宽度以适应。

4 个答案:

答案 0 :(得分:0)

我建议将第二列的宽度从“auto”设置为“*”,就像在第一列中一样。然后设置MaxWidth,这样组合框在调整大小时就不会变大。

boolean isChecked = sharedPref.getBoolean("isChecked", false);

答案 1 :(得分:0)

使用更简单的数据网格可以重现问题:只需将一个星号大小的列放在另一个不是星号的列的前面。只要整个网格大小保持不变,布局过程就不会尝试将列缩小到左侧,以便为更多空间提供列。

以下解决方案基于https://stackoverflow.com/a/5651287/5265292

建立一些事件,指示可能需要的列调整大小,然后删除星号列宽,更新布局,恢复列宽。在我的示例中,我使用了SelectionChanged事件,需要调度布局更新才能正常工作:

void dg1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.OriginalSource is ComboBox)
    {
        Dispatcher.BeginInvoke(new Action(() =>
            {
                dg1.Columns[0].Width = new DataGridLength();
                dg1.UpdateLayout();
                dg1.Columns[0].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
            }));
    }
}

我的示例XAML包含代码背后的项目源:

<Grid x:Name="grid1">
    <Grid.Resources>
        <CollectionViewSource x:Key="ComboBoxItemsSource" Source="{Binding ComboItems}"/>
    </Grid.Resources>
    <DataGrid
        x:Name="dg1"
        ItemsSource="{Binding DataItems}"
        AutoGenerateColumns="False"
        SelectionChanged="dg1_SelectionChanged">
        <DataGrid.Columns>
            <DataGridTextColumn
                Width="*"/>
            <DataGridComboBoxColumn
                Header="B"
                ItemsSource="{Binding Source={StaticResource ComboBoxItemsSource}}"
                SelectedItemBinding="{Binding Text}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

为了完整起见,初始化和视图模型:

public MainWindow()
{
    InitializeComponent();
    grid1.DataContext = vm = new MyViewModel()
    {
        DataItems =
        {
            new ItemVM(),
        },
        ComboItems =
        {
            "A",
            "AAAAAAAAAAAAAAAAAAAAAAA"
        }
    };
}


public class MyViewModel
{
    private ObservableCollection<ItemVM> _DataItems = new ObservableCollection<ItemVM>();
    public ObservableCollection<ItemVM> DataItems
    {
        get { return _DataItems; }
    }

    private ObservableCollection<string> _ComboItems = new ObservableCollection<string>();
    public ObservableCollection<string> ComboItems
    {
        get { return _ComboItems; }
    }
}


public class ItemVM : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChangedEvent([CallerMemberName]string prop = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(prop));
    }

    private string _Text;
    public string Text
    {
        get { return _Text; }
        set { _Text = value; RaisePropertyChangedEvent(); }
    }
}

答案 2 :(得分:0)

尝试将DataTemplate直接添加到'DataGridTemplateColumn'。

我会做这样的事情:

<DataGridTemplateColumn Width="Auto"
                        CanUserReorder="False" CanUserResize="False"
                        Header="Action">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
           <ComboBox Margin="2 2 2 2"
                     ItemsSource="{Binding Path=DataContext.AvailableActions,
                                           Mode=OneTime,
                                           RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                     SelectedValue="{Binding Path=Action, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                     SelectedValuePath="Key"
                     DisplayMemberPath="Value"
                     IsEditable="False"
                     IsSynchronizedWithCurrentItem="False"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

答案 3 :(得分:0)

您是否尝试使用Horizo​​ntalAlignment和/或Horizo​​ntalContentAlignment来对组合框进行拉伸?