【发布时间】:2018-09-23 22:26:44
【问题描述】:
我有一个 MVVM WPF 应用程序。
我在 WPF 数据网格中有一个 DataGridTextColumn。我想将其宽度属性绑定到转换器并将其单元格值传递给它。对于这一列,在某些情况下,该列的所有单元格都是空的,所以我还想将列宽设置为固定值,如果所有单元格都是空的,则为 20(与其 MinWidth 相同),否则为 50。问题是没有调用该转换器。
为了简化和关注有趣的部分,我只在这里发布相关代码:
<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>
转换器:
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。我认为使用转换器是个好主意,但从不调用转换器。为什么?
更新: Finllay 我已经完成了@Andy 的建议:将视图模型中的属性绑定到视图上的 datagridtextcolumn 宽度属性。视图模型上的这个属性遍历所有列单元格,然后相应地设置宽度。见下文。我的问题是视图模型上的这个属性 'EntryDateColumnWidth' 仅在应用程序启动时第一次触发,然后在调用 OnPropertyChanged("EntryDateColumnWidth") 时,它不会被引发。
查看模型:
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));
}
}
}
另外,从视图模型中,当我为数据网格设置项目列表时,我执行:
OnPropertyChanged("EntryDateColumnWidth");
此属性返回一个 DataGridLength 对象,因为当任何列单元格不为空时,我需要将宽度设置为自动。
注意:ViewModelBase 是实现 INotifyPropertyChanged 的抽象类。
查看:
<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>
类绑定代理:
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:
依赖对象类:
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):
<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)中:
<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>
窗口:
<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>
查看模型:
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);
}
}
但是列宽没有更新...
【问题讨论】:
-
entrydate 在哪里,它到底是什么?您的专栏正在绑定 DataCommanda。根据您的描述,您必须遍历所有这些并检查它们是否为空。您意识到“输入日期”的标题不适合 20 宽的列吗?
-
这和你的其他问题不是同一个问题吗?将属性添加到您的视图模型并使用带有 trueforall 的 linq 来查看所有特定列是否为空。然后设置你的属性。使用数据触发器设置宽度或将其设置为双倍并直接绑定宽度。
-
@Andy 这是一个错误,请参阅我的更新。 EntryDate 来自绑定到 DataGrid 的 Itemsource。我的意思是尽管所有列单元格都是空的,但列宽与其标题标题一样宽。
-
我明白这一点。您需要迭代整个集合并检查每个条目日期。正如我所解释的。忘记转换器。在您的视图模型中执行此操作。如果您没有视图模型,请添加一个视图模型,并将绑定到的任何 itemssource 放在那里。然后使用linq检查是否所有entrydates都为null并设置一个属性。
-
@Andy 我已经完成了您在视图模型中使用属性的建议。我现在的问题是这个属性永远不会被解雇。查看我的最新更新。
标签: wpf .net-3.5 converter ivalueconverter datagridtextcolumn