我有一个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。我认为使用转换器将是一个好主意,但转换器从来没有被调用。为什么?
UPDATE: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对象,因为当任何列单元格不为空时,我需要将宽度设置为auto。
注意事项: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>类BindingProxy
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);
}
}但是列宽没有更新..。
发布于 2018-04-16 19:06:55
好的,这演示了我所描述的原理,它有点快,有点脏。
将依赖项对象定义为新类。
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)));
}
}在资源字典中创建实例。
<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中合并该资源字典:
<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秒后,它被实例化。
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));
}
}
}把它放在我的窗户里:
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> 当我运行它时,我从一个狭窄的专栏开始。坐在那里观察它一段时间,它会改变到自动宽度和宽度。
发布于 2018-04-13 14:43:37
我认为使用转换器将是一个好主意,但转换器从来没有被调用。为什么?
因为DataGridTextColumn不继承DataContext,不能像那样绑定到EntryDate属性。
我的最终目标是在所有单元格为空时将列宽度设置为20,否则将其宽度设置为50。
然后,您可以遍历DataGrid的ItemsSource中的所有项,并检查它们的EntryDate属性的值,例如:
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。如果它是DateTime或Nullable<DateTime>,您可以检查它分别等于default(DateTime)还是default(DateTime?)。
https://stackoverflow.com/questions/49819058
复制相似问题