2016-01-26 64 views
0

我有问题在他的样式中设置触发器内的DataGrid的ColumnWidth。WPF DataGrid:在触发器中设置ColumnWidth

我有这样的:

<DataGrid ItemsSource="{Binding Data}"> 
    <DataGrid.Style> 
     <Style TargetType="DataGrid"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Data.Count}" Value="2"> 
        <Setter Property="Background" Value="LightGreen" /> 
        <Setter Property="ColumnWidth" Value="400" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </DataGrid.Style> 
</DataGrid> 

在两行情况下,我想,以填补与绿色背景,使更广泛的列,但我不仅可以实现绿色背景..为什么columnWidth时设置不管用?

[![在这里输入的形象描述] [1] [1]

它的工作原理,如果我把columnWidth时触发外设置..但我不希望这个..

<DataGrid ItemsSource="{Binding Data}"> 
    <DataGrid.Style> 
     <Style TargetType="DataGrid"> 
      <Setter Property="ColumnWidth" Value="400" /> 

      <Style.Triggers> 
       <DataTrigger Binding="{Binding Data.Count}" Value="2"> 
        <Setter Property="Background" Value="LightGreen" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </DataGrid.Style> 
</DataGrid> 

谢谢!

解决:

最后我有一个绑定到我的数据和转换器建立ColumnWidt:

<DataGrid ColumnWidth="{Binding Data, Converter={StaticResource DataToColumnWidthConverter}}" ItemsSource="{Binding Data}" IsReadOnly="True" MaxHeight="300" > 

转换器:

[ValueConversion(typeof(DataTable), typeof(DataGridLength))] 
public class DataToColumnWidthConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     DataTable dt = value as DataTable; 

     if (dt != null && dt.Rows.Count == 2) 
     { 
      return new DataGridLength(400); 
     } 

     return new DataGridLength(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return null; 
    } 
} 

这是OK的我,因为我数据不会改变执行时间的行数,所以ColumnWidth只需要在开始时计算一次。

谢谢全部

回答

1

请尝试下一个解决方案。正如你所看到的,我使用了一个代理对象将一个主数据上下文传递给每个数据网格单元。另外还有一个DataTrigger,它在隐藏列的可见性发生变化时有效,并且有一个附加属性有助于控制实际列的宽度。 下面是代码:

XAML代码

<Window x:Class="DataGridSoHelpAttempt.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:dataGridSoHelpAttempt="clr-namespace:DataGridSoHelpAttempt" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    Title="MainWindow" Height="350" Width="525" x:Name="This"> 
<Window.DataContext> 
    <dataGridSoHelpAttempt:MainViewModel/> 
</Window.DataContext> 
<Grid x:Name="MyGrid"> 
    <Grid.Resources> 
     <dataGridSoHelpAttempt:FreezableProxyClass x:Key="ProxyElement" ProxiedDataContext="{Binding Source={x:Reference This}, Path=DataContext}"/> 
    </Grid.Resources> 
    <DataGrid x:Name="MyDataGrid" ItemsSource="{Binding DataSource}" AutoGenerateColumns="False"> 

     <DataGrid.Columns> 
      <DataGridTextColumn Header="Name" Binding="{Binding Name}"/> 
      <DataGridTextColumn Header="Description" Binding="{Binding Description}" Visibility="{Binding Source={StaticResource ProxyElement}, 
       Path=ProxiedDataContext.Visibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
      <DataGridTextColumn Header="Comments" Binding="{Binding Comments}"/> 
      <DataGridTextColumn Header="Price (click to see total)" Binding="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
     </DataGrid.Columns> 
     <DataGrid.Resources> 
      <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding Source={StaticResource ProxyElement}, 
       Path=ProxiedDataContext.Visibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="Visible"> 
         <Setter Property="Width" Value="200"></Setter> 
         <Setter Property="dataGridSoHelpAttempt:DataGridAttached.ColumnActualWidth" Value="200"/> 
        </DataTrigger> 
        <DataTrigger Binding="{Binding Source={StaticResource ProxyElement}, 
       Path=ProxiedDataContext.Visibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="Collapsed"> 
         <Setter Property="Width" Value="400"></Setter> 
         <Setter Property="dataGridSoHelpAttempt:DataGridAttached.ColumnActualWidth" Value="400"/> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </DataGrid.Resources> 
    </DataGrid> 
    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Bottom"> 
     <Button Content="Show Description" Command="{Binding Command}"></Button> 
    </StackPanel> 
</Grid></Window> 

附加属性代码

public class DataGridAttached 
{ 
    public static readonly DependencyProperty ColumnActualWidthProperty = DependencyProperty.RegisterAttached(
     "ColumnActualWidth", typeof (double), typeof (DataGridAttached), new PropertyMetadata(default(double), ColumnActualWidthPropertyChanged)); 

    private static void ColumnActualWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var data = d.FindParent<DataGrid>(); 
     var control = (d as Control); 
     if(data == null || control == null) return; 
     data.Columns.ToList().ForEach(column => 
     { 
      var cellWidth = control.Width; 
      if(double.IsNaN(cellWidth) || double.IsInfinity(cellWidth)) return; 
      column.Width = cellWidth; 
     }); 
    } 

    public static void SetColumnActualWidth(DependencyObject element, double value) 
    { 
     element.SetValue(ColumnActualWidthProperty, value); 
    } 

    public static double GetColumnActualWidth(DependencyObject element) 
    { 
     return (double) element.GetValue(ColumnActualWidthProperty); 
    } 
} 

视图模型和模型

public class MainViewModel:BaseObservableObject 
{ 
    private Visibility _visibility; 
    private ICommand _command; 
    private Visibility _totalsVisibility; 
    private double _totalValue; 
    private double _columnWidth; 

    public MainViewModel() 
    { 
     Visibility = Visibility.Collapsed; 
     TotalsVisibility = Visibility.Collapsed; 
     DataSource = new ObservableCollection<BaseData>(new List<BaseData> 
     { 
      new BaseData {Name = "Uncle Vania", Description = "A.Chekhov, play", Comments = "worth reading", Price = 25}, 
      new BaseData {Name = "Anna Karenine", Description = "L.Tolstoy, roman", Comments = "worth reading", Price = 35}, 
      new BaseData {Name = "The Master and Margarita", Description = "M.Bulgakov, novel", Comments = "worth reading", Price = 56}, 
     }); 
    } 

    public ICommand Command 
    { 
     get 
     { 
      return _command ?? (_command = new RelayCommand(VisibilityChangingCommand)); 
     } 
    } 

    private void VisibilityChangingCommand() 
    { 
     Visibility = Visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed; 
     ColumnWidth = Visibility == Visibility.Visible ? 200d : 400d; 
    } 

    public ObservableCollection<BaseData> DataSource { get; set; } 

    public Visibility Visibility 
    { 
     get { return _visibility; } 
     set 
     { 
      _visibility = value; 
      OnPropertyChanged(); 
     } 
    } 

    public ObservableCollection<BaseData> ColumnCollection 
    { 
     get { return DataSource; } 
    } 

    public Visibility TotalsVisibility 
    { 
     get { return _totalsVisibility; } 
     set 
     { 
      _totalsVisibility = value; 
      OnPropertyChanged(); 
     } 
    } 

    public double TotalValue 
    { 
     get { return ColumnCollection.Sum(x => x.Price); } 
    } 

    public double ColumnWidth 
    { 
     get { return _columnWidth; } 
     set 
     { 
      _columnWidth = value; 
      OnPropertyChanged(); 
     } 
    } 
} 

public class BaseData:BaseObservableObject 
{ 
    private string _name; 
    private string _description; 
    private string _comments; 
    private int _price; 

    public virtual string Name 
    { 
     get { return _name; } 
     set 
     { 
      _name = value; 
      OnPropertyChanged(); 
     } 
    } 

    public virtual object Description 
    { 
     get { return _description; } 
     set 
     { 
      _description = (string) value; 
      OnPropertyChanged(); 
     } 
    } 

    public string Comments 
    { 
     get { return _comments; } 
     set 
     { 
      _comments = value; 
      OnPropertyChanged(); 
     } 
    } 

    public int Price 
    { 
     get { return _price; } 
     set 
     { 
      _price = value; 
      OnPropertyChanged(); 
     } 
    } 
} 

可冻结助手

public class FreezableProxyClass : Freezable 
{ 
    protected override Freezable CreateInstanceCore() 
    { 
     return new FreezableProxyClass(); 
    } 


    public static readonly DependencyProperty ProxiedDataContextProperty = DependencyProperty.Register(
     "ProxiedDataContext", typeof (object), typeof (FreezableProxyClass), new PropertyMetadata(default(object))); 

    public object ProxiedDataContext 
    { 
     get { return (object) GetValue(ProxiedDataContextProperty); } 
     set { SetValue(ProxiedDataContextProperty, value); } 
    } 
} 

助手

public static class VisualTreeHelperExtensions 
{ 
    public static T FindParent<T>(this DependencyObject child) where T : DependencyObject 
    { 
     while (true) 
     { 
      //get parent item 
      DependencyObject parentObject = VisualTreeHelper.GetParent(child); 

      //we've reached the end of the tree 
      if (parentObject == null) return null; 

      //check if the parent matches the type we're looking for 
      T parent = parentObject as T; 
      if (parent != null) 
       return parent; 
      child = parentObject; 
     } 
    } 
} 

public class BaseObservableObject : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser) 
    { 
     var propName = ((MemberExpression)raiser.Body).Member.Name; 
     OnPropertyChanged(propName); 
    } 

    protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null) 
    { 
     if (!EqualityComparer<T>.Default.Equals(field, value)) 
     { 
      field = value; 
      OnPropertyChanged(name); 
      return true; 
     } 
     return false; 
    } 
} 

public class RelayCommand : ICommand 
{ 
    private readonly Func<bool> _canExecute; 
    private readonly Action _execute; 

    public RelayCommand(Action execute) 
     : this(() => true, execute) 
    { 
    } 

    public RelayCommand(Func<bool> canExecute, Action execute) 
    { 
     _canExecute = canExecute; 
     _execute = execute; 
    } 

    public bool CanExecute(object parameter = null) 
    { 
     return _canExecute(); 
    } 

    public void Execute(object parameter = null) 
    { 
     _execute(); 
    } 

    public event EventHandler CanExecuteChanged; 
} 

public class RelayCommand<T> : ICommand 
    where T:class 
{ 
    private readonly Predicate<T> _canExecute; 
    private readonly Action<T> _execute; 

    public RelayCommand(Action<T> execute):this(obj => true, execute) 
    { 
    } 

    public RelayCommand(Predicate<T> canExecute, Action<T> execute) 
    { 
     _canExecute = canExecute; 
     _execute = execute; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return _canExecute(parameter as T); 
    } 

    public void Execute(object parameter) 
    { 
     _execute(parameter as T); 
    } 

    public event EventHandler CanExecuteChanged; 
} 

它是完整的测试解决方案,你应该把这个是如何工作的只是想法。如果您遇到代码问题,我很乐意提供帮助。

问候。

+0

谢谢!我用另一种方式解决了我的问题,但是我受到了你的解决方案的影响!非常感谢! – Lamelas84

1
  1. DataGrid删除ItemsSource,并将其移动到DataTrigger
  2. 要在初始绑定后设置ColumnWidth,需要重新绑定。你不能从代码中设置ColumnWidth,它不会有任何作用。对于ColumnWidth有任何影响,您需要先删除DataGridDataContext/ItemsSource(设置为空),然后重新指定它。

因此,如果您在某处更改集合,则必须先将DataGrid的DataContext设置为null,然后重新指定它。看看我在按钮点击下面做了什么。 以下代码不言自明。我已经写了案件变换器的MarkupExtension时Data.Count不会4.

<DataGrid x:Name="Dgrid" Margin="0,58,0,0"> 
    <DataGrid.Style> 
     <Style TargetType="DataGrid"> 
      <Style.Triggers> 
      <DataTrigger Binding="{Binding Data.Count}" Value="4"> 
       <Setter Property="ColumnWidth" Value="200" /> 
       <Setter Property="ItemsSource" Value="{Binding Data}" /> 
       <Setter Property="Background" Value="LightGreen" />        
      </DataTrigger> 
      <DataTrigger Binding="{Binding Data.Count, Converter={local:CountToBool}}" Value="true"> 
       <Setter Property="ColumnWidth" Value="100" /> 
       <Setter Property="ItemsSource" Value="{Binding Data}" /> 
       <Setter Property="Background" Value="Red" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </DataGrid.Style> 
    </DataGrid> 

转换器:

public class CountToBoolConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      if ((int)value != 4) 
       return true; 

      return false; 
     } 

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

    public class CountToBoolExtension : MarkupExtension 
    { 
     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      return new CountToBoolConverter(); 
     } 
    } 

代码隐藏:columnWidth时根据

ViewModel vm = new ViewModel(); 

// removing 2 items and reassigning DataContext to viewmodel. 
private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Dgrid.DataContext = null; 

    vm.Students.RemoveAt(1); 
    vm.Students.RemoveAt(2); 

    Dgrid.DataContext = vm; 
} 

上面的代码将改变Data.Count值并且在运行时更改Collection中的记录数时正常工作。

+0

谢谢!我用另一种方式解决了我的问题,但是我受到了你的解决方案的影响!非常感谢! – Lamelas84