首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >设置DataGridTextColumn宽度

设置DataGridTextColumn宽度
EN

Stack Overflow用户
提问于 2018-04-13 14:15:27
回答 2查看 2.3K关注 0票数 1

我有一个MVVM WPF应用程序。

我在WPF数据集中有一个DataGridTextColumn。我希望将其宽度属性绑定到转换器,并将其单元格值传递给它。对于该列,在某些情况下,该列的所有单元格都是空的,因此我还希望将列宽度设置为固定值,20 (与其MinWidth相同),以防所有单元格为空,否则为50。问题是转换器没有被调用。

为了简化和关注有趣的部分,我只在这里发布了相关代码:

代码语言:javascript
复制
 <DataGrid  Grid.Row="1"                          
               AutoGenerateColumns="False" 
               ItemsSource="{Binding Path=MyListOfItems}" 
               VerticalAlignment="Stretch" IsReadOnly="True" 
               SelectionMode="Single" ColumnWidth="*" 
               >

<DataGridTextColumn 
      CellStyle="{StaticResource MyDataGridCellStyle}"
      Binding="{Binding Path=EntryDate, StringFormat=\{0:dd/MM/yyyy\}}" 
      Header="Entry Date" 
      Width="{Binding Path=EntryDate, Converter={StaticResource ColumnWidthConverter}}"
      HeaderStyle="{DynamicResource CenterGridHeaderStyle}">

</DataGridTextColumn> 

 </DataGrid>

变换器

代码语言:javascript
复制
public class ColumnWidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string cellContent= (string)value;

        return (string.IsNullOrEmpty(cellContent.Trim()) ? 20 : 50);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

我的最终目标是在所有单元格为空时将列宽度设置为20,否则将其宽度设置为50。我认为使用转换器将是一个好主意,但转换器从来没有被调用。为什么?

UPDATE:Finllay我已经做了@Andy建议的工作:将一个属性从视图模型绑定到视图上的datagridtextcolumn属性。视图模型上的此属性遍历所有列单元格,然后相应地设置宽度。见下文。我的问题是,视图模型上的这个属性'EntryDateColumnWidth‘仅在启动应用程序时才会触发,然后在调用OnPropertyChanged("EntryDateColumnWidth")时才不会引发。

视图模型

代码语言:javascript
复制
public class MyMainViewModel : ViewModelBase
{
  public DataGridLength EntryDateColumnWidth
  {
      get
      {
          bool isEmpty = this.MyListOfItems.TrueForAll(i => string.IsNullOrEmpty(i.EntryDate.ToString().Trim()));

          return (isEmpty ? 20 : new DataGridLength(0, DataGridLengthUnitType.Auto));
      }
  }
}

此外,从视图模型中,当我设置了数据集的项列表时,我执行以下操作:

代码语言:javascript
复制
OnPropertyChanged("EntryDateColumnWidth");

此属性返回一个DataGridLength对象,因为当任何列单元格不为空时,我需要将宽度设置为auto。

注意事项:ViewModelBase是一个实现INotifyPropertyChanged的抽象类。

视图

代码语言:javascript
复制
<DataGrid  Grid.Row="1"                          
           AutoGenerateColumns="False" 
           ItemsSource="{Binding Path=MyListOfItems}" 
           VerticalAlignment="Stretch" IsReadOnly="True" 
           SelectionMode="Single" ColumnWidth="*">

<DataGrid.Resources>
   <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

<DataGridTextColumn 
      CellStyle="{StaticResource MyDataGridCellStyle}"
      Binding="{Binding Path=EntryDate, StringFormat=\{0:dd/MM/yyyy\}}" 
      Header="Entry Date" 
      Width="{Binding Data.EntryDateColumnWidth, Source={StaticResource proxy}}"
      HeaderStyle="{DynamicResource CenterGridHeaderStyle}">

</DataGridTextColumn> 

</DataGrid>

类BindingProxy

代码语言:javascript
复制
namespace MyApp.Classes
{
    public class BindingProxy : Freezable
    {
        #region Overrides of Freezable

        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }

        #endregion

        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }
}

更新2

依赖对象类

代码语言:javascript
复制
namespace My.WPF.App.Classes
{
    public class BridgeDO: DependencyObject
    {
        public DataGridLength DataComandaColWidth
        {
            get { return (DataGridLength)GetValue(DataComandaColWidthProperty); }
            set { SetValue(DataComandaColWidthProperty, value); }
        }

        public static readonly DependencyProperty EntryDateColWidthProperty =
            DependencyProperty.Register("EntryDateColWidth", 
                                        typeof(DataGridLength), 
                                        typeof(BridgeDO),                                         
                                        new PropertyMetadata(new DataGridLength(1, DataGridLengthUnitType.Auto)));
    }
}

资源字典(DictionaryDO.xaml)中的实例

代码语言:javascript
复制
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:My.WPF.App.Classes">
    <local:BridgeDO x:Key="DO"/>
</ResourceDictionary>

将其合并为资源字典(app.xaml)

代码语言:javascript
复制
<Application x:Class="My.WPF.Apps.MyApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"
    xmlns:local="clr-namespace:My.WPF.Apps.MyApp"
    StartupUri="Main.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionaries/DictionaryDO.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <!-- Styles -->
        </ResourceDictionary>
    </Application.Resources>
</Application>

窗口

代码语言:javascript
复制
<Window x:Name="MainWindow" x:Class="My.WPF.Apps.MyApp.wMain"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Window.Resources>
   <!-- Resources -->
</Window.Resources>

<DataGrid  Grid.Row="1"                          
           AutoGenerateColumns="False" 
           ItemsSource="{Binding Path=MyListOfItems}" 
           VerticalAlignment="Stretch" IsReadOnly="True" 
           SelectionMode="Single" ColumnWidth="*">

<DataGrid.Resources>
   <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

<DataGridTextColumn 
      CellStyle="{StaticResource MyDataGridCellStyle}"
      Binding="{Binding Path=EntryDate, StringFormat=\{0:dd/MM/yyyy\}}" 
      Header="Entry Date" 
      Width="{Binding EntryDateColWidth, Source={StaticResource DO}}"
      HeaderStyle="{DynamicResource CenterGridHeaderStyle}">

</DataGridTextColumn> 

</DataGrid>

</Window>

视图模型

代码语言:javascript
复制
public class myMainViewModel : ViewModelBase 
{
   private BridgeDO _do;
   public myMainViewModel(IView view)
   {
      _view = view;
      _do = Application.Current.Resources["DO"] as BridgeDO;            
   }


   private void BackgroundWorker_DoWork()
   {
      // Do some stuff
      SetColumnWidth();
   }


   private void SetColumnWidth()
   {
      _view.GetWindow().Dispatcher.Invoke(new Action(delegate
       {
          bool isEmpty = this.MyListOfItems.TrueForAll(e => !e.EntryDate.HasValue);
          _do.SetValue(BridgeDO.EntryDateColWidthProperty, isEmpty ? new DataGridLength(22.0) : new DataGridLength(1, DataGridLengthUnitType.Auto));

            }), DispatcherPriority.Render);
   }
}

但是列宽没有更新..。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-16 19:06:55

好的,这演示了我所描述的原理,它有点快,有点脏。

将依赖项对象定义为新类。

代码语言:javascript
复制
using System.Windows;
using System.Windows.Controls;

namespace wpf_12
{
    public class BridgeDO : DependencyObject
    {
        public DataGridLength ColWidth
        {
            get { return (DataGridLength)GetValue(ColWidthProperty); }
            set { SetValue(ColWidthProperty, value); }
        }
        public static readonly DependencyProperty ColWidthProperty =
            DependencyProperty.Register("ColWidth", typeof(DataGridLength), typeof(BridgeDO), new PropertyMetadata(new DataGridLength(20.0)));
    }
}

在资源字典中创建实例。

代码语言:javascript
复制
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:wpf_12">
    <local:BridgeDO x:Key="DO"/>
</ResourceDictionary>

在app.xaml中合并该资源字典:

代码语言:javascript
复制
<Application x:Class="wpf_12.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wpf_12"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

快速和肮脏的视图模型,这将改变列的宽度自动6秒后,它被实例化。

代码语言:javascript
复制
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace wpf_12
{
    public class MainWIndowViewModel
    {
        public ObservableCollection<object> Items { get; set; } = new ObservableCollection<object>
        {   new { Name="Billy Bob", ID=1},
            new { Name="Peter Parker", ID=2},
            new { Name="Sherlock Holmes", ID=2}
        };

        public MainWIndowViewModel()
        {
            ChangeWidth();
        }
        private async void ChangeWidth()
        {
            await Task.Delay(6000);
            var _do = Application.Current.Resources["DO"] as BridgeDO;
            _do.SetCurrentValue(BridgeDO.ColWidthProperty, new DataGridLength(1, DataGridLengthUnitType.Auto));
        }
    }
}

把它放在我的窗户里:

代码语言:javascript
复制
        Name="Window"
    >
    <Window.DataContext>
        <local:MainWIndowViewModel/>
    </Window.DataContext>

    <Window.Resources>

    </Window.Resources>
    <Grid>
        <DataGrid ItemsSource="{Binding Items}"
                  AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" Width="{Binding ColWidth, Source={StaticResource DO}}"/>
                <DataGridTextColumn Binding="{Binding ID}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>  

当我运行它时,我从一个狭窄的专栏开始。坐在那里观察它一段时间,它会改变到自动宽度和宽度。

票数 1
EN

Stack Overflow用户

发布于 2018-04-13 14:43:37

我认为使用转换器将是一个好主意,但转换器从来没有被调用。为什么?

因为DataGridTextColumn不继承DataContext,不能像那样绑定到EntryDate属性。

我的最终目标是在所有单元格为空时将列宽度设置为20,否则将其宽度设置为50。

然后,您可以遍历DataGridItemsSource中的所有项,并检查它们的EntryDate属性的值,例如:

代码语言:javascript
复制
dgg.Loaded += (s, e) => 
{
    bool isEmpty = true;
    foreach(var item in dgg.Items.OfType<Item>())
    {
        if (!string.IsNullOrEmpty(item.EntryDate))
        {
            isEmpty = false;
            break;
        }
    }

    //set the Width of the column (at index 0 in this sample)
    dgg.Columns[0].Width = isEmpty? 20 : 500;
};

注意:在这个特殊的例子中,我假设EntryDate确实是一个string。如果它是DateTimeNullable<DateTime>,您可以检查它分别等于default(DateTime)还是default(DateTime?)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49819058

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档