MVVM WPF アプリケーションがあります。
WPF データグリッドに DataGridTextColumn があります。width プロパティをコンバーターにバインドし、セル値を渡したいと思います。この列では、この列のすべてのセルが空の場合があるため、すべてのセルが空の場合は列幅を固定値 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>
クラス 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);
}
}
しかし、列幅は更新されていません...