2012-05-29 158 views
7

我有一個標準的(WPF工具包)數據網格。一些列(明確定義的)必須以百分比顯示。如果值低於0,則某些列必須以紅色顯示(兩組列不相同)。我試圖分別使用StringFormatStyle來實現這些要求。我的XAML:WPF datagrid:轉換器和StringFormat

<Window xmlns:local="clr-namespace:myNamespace" 
     xmlns:tk="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"> 
    <Window.Resources> 
     <local:ValueConverter x:Key="valueToForeground" /> 
     <Style TargetType="{x:Type tk:DataGridCell}"> 
      <Setter Property="Foreground" 
        Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource valueToForeground}}" /> 
     </Style> 
    </Window.Resources> 
    <Grid> 
     <tk:DataGrid AutoGenerateColumns="False" 
        ItemsSource="{Binding Path=myClass/myProperty}"> 
      <tk:DataGrid.Columns> 
       <tk:DataGridTextColumn Header="A" 
             Binding="{Binding colA}" /> 
       <tk:DataGridTextColumn Header="B" 
             Binding="{Binding colB, StringFormat=\{0:P\}}" /> 
       <tk:DataGridTextColumn Header="C" 
             Binding="{Binding colC, StringFormat=\{0:P\}}" /> 
       <tk:DataGridTextColumn Header="D" 
             Binding="{Binding colD, StringFormat=\{0:P\}}" /> 
      </tk:DataGrid.Columns> 
     </tk:DataGrid> 
    </Grid> 
</Window> 

和相關的轉換器:

namespace myNamespace 
{ 
    public class ValueConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      SolidColorBrush brush = new SolidColorBrush(Colors.Black); 

      Double doubleValue = 0.0; 
      if (value != null) 
      { 
       if (Double.TryParse(value.ToString(), out doubleValue)) 
       { 
        if (doubleValue < 0) 
         brush = new SolidColorBrush(Colors.Red); 
       } 
      } 
      return brush; 
     } 

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

我覺得這一切都非常標準,但問題是,它通過StringFormat走後轉換得到Text價值,並在此指出很難正確解析它(因爲實際上,並非所有列都具有相同的格式)。如果我拿出StringFormats,轉換器工作正常,文字顯示爲紅色。我錯過了明顯的東西嗎?有沒有簡單的方法來解決這個問題?我現在唯一能想到的就是將格式轉換爲不同的轉換器,我不相信這會起作用。

回答

5

我們有我們需要一個不同的Path物業類似的情況Binding但其他類似的CellStyle每個DataGridColumn。我們用自定義MarkupExtension解決了這個問題。在你的情況應該是這樣的

<tk:DataGrid AutoGenerateColumns="False" 
       ItemsSource="{Binding MyItems}"> 
    <tk:DataGrid.Columns> 
     <tk:DataGridTextColumn Header="A" 
           Binding="{Binding colA}" /> 
     <tk:DataGridTextColumn Header="B" 
           Binding="{Binding colB, StringFormat=\{0:P\}}" 
           CellStyle="{markup:ForegroundCellStyle PropertyName=colB}"/> 
     <tk:DataGridTextColumn Header="C" 
           Binding="{Binding colC, StringFormat=\{0:P\}}" 
           CellStyle="{markup:ForegroundCellStyle PropertyName=colC}"/> 
     <tk:DataGridTextColumn Header="D" 
           Binding="{Binding colD, StringFormat=\{0:P\}}" 
           CellStyle="{markup:ForegroundCellStyle PropertyName=colD}"/> 
    </tk:DataGrid.Columns> 
</tk:DataGrid> 

然後ForegroundCellStyleExtension創建取決於StyleDataGridCellPropertyName

ForegroundCellStyleExtension

public class ForegroundCellStyleExtension : MarkupExtension 
{ 
    public ForegroundCellStyleExtension() { } 
    public ForegroundCellStyleExtension(string propertyName) 
    { 
     PropertyName = propertyName; 
    } 

    public string PropertyName 
    { 
     get; 
     set; 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     IProvideValueTarget service = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); 
     DependencyObject targetObject = service.TargetObject as DependencyObject; 
     if (targetObject == null) 
     { 
      return null; 
     } 

     Binding foregroundBinding = new Binding 
     { 
      Path = new PropertyPath(PropertyName), 
      Converter = new ValueConverter() 
     }; 
     Style foregroundCellStyle = new Style(typeof(DataGridCell)); 
     foregroundCellStyle.Setters.Add(new Setter(DataGridCell.ForegroundProperty, foregroundBinding)); 

     return foregroundCellStyle; 
    } 
} 

另外,如果你有一些其他Setters等。你想使用它們,然後它們可以被另一個參數包含到中。

<Window.Resources> 
    <Style x:Key="dataGridCellStyle" TargetType="{x:Type tk:DataGridCell}"> 
     <Setter Property="Background" Value="Blue"/> 
    </Style> 
</Window.Resources> 
<!-- ... --> 
<tk:DataGridTextColumn Header="B" 
         Binding="{Binding colB, StringFormat=\{0:P\}}" 
         CellStyle="{markup:ForegroundCellStyle colB, {StaticResource dataGridCellStyle}}"/> 

而且ForegroundCellStyleExtension然後將使用第二個參數爲BasedOnDataGridCellStyle

ForegroundCellStyleExtension與BasedOn

public class ForegroundCellStyleExtension : MarkupExtension 
{ 
    public ForegroundCellStyleExtension() { } 
    public ForegroundCellStyleExtension(string propertyName, Style basedOnCellStyle) 
    { 
     PropertyName = propertyName; 
     BasedOnCellStyle = basedOnCellStyle; 
    } 

    public string PropertyName 
    { 
     get; 
     set; 
    } 
    public Style BasedOnCellStyle 
    { 
     get; 
     set; 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     IProvideValueTarget service = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); 
     DependencyObject targetObject = service.TargetObject as DependencyObject; 
     if (targetObject == null) 
     { 
      return null; 
     } 

     Binding foregroundBinding = new Binding 
     { 
      Path = new PropertyPath(PropertyName), 
      Converter = new ValueConverter() 
     }; 
     Style foregroundCellStyle = new Style(typeof(DataGridCell), BasedOnCellStyle); 
     foregroundCellStyle.Setters.Add(new Setter(DataGridCell.ForegroundProperty, foregroundBinding)); 

     return foregroundCellStyle; 
    } 
} 
+0

這看起來好像會起作用,但我沒有足夠的時間來測試它。不管怎麼說,還是要謝謝你! – vlad

+0

這是一個更好的重用解決方案,並且像魅力一樣工作!這應該是真正的答案 – DLeh

2

指定單元格樣式爲每列如下:

<DataGridTextColumn Header="ColA" Binding="{Binding colA, StringFormat=\{0:P\}}"> 
    <DataGridTextColumn.CellStyle> 
     <Style TargetType="DataGridCell"> 
      <Setter Property="Foreground" 
        Value="{Binding colA, Converter={StaticResource valueToForeground}}" /> 
     </Style> 
    </DataGridTextColumn.CellStyle> 
</DataGridTextColumn> 

<DataGridTextColumn Header="ColB" Binding="{Binding colB, StringFormat=\{0:P\}}"> 
    <DataGridTextColumn.CellStyle> 
     <Style TargetType="DataGridCell"> 
      <Setter Property="Foreground" 
        Value="{Binding colB, Converter={StaticResource valueToForeground}}" /> 
     </Style> 
    </DataGridTextColumn.CellStyle> 
</DataGridTextColumn> 

... 

和修改器

public class ValueConverter : IValueConverter 
{ 
    public object Convert(
       object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return ((double) value < 0) ? Brushes.Red : Brushes.Black; 
    } 

    public object ConvertBack(
       object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return Binding.DoNothing; 
    } 
} 

enter image description here

+0

我想這一點,但沒有奏效。 – vlad

+1

@vlad:它絕對有效,我忘了添加更新的值轉換器 – Phil

+0

我會給它一個鏡頭,謝謝。 – vlad

1

最簡單的方法我想通了,就是你的整個項目綁定,而不是item/content.text僅限於您的轉換器。然後你就可以做你想做的事情與你的細胞需要擔心的項目和參數值。

在您的單元格樣式:

<Setter Property="Foreground" 
    Value="{Binding Converter={StaticResource valueToForeground}}" /> 

,並在你的代碼轉換器:

public object Convert(object value, Type targetType, 
    object parameter, System.Globalization.CultureInfo culture) 
{ 
    SolidColorBrush brush = new SolidColorBrush(Colors.Black);  

    Double doubleValue = 0.0; 
    if (value != null) 
    { 
     mydatatype data = value as mydatatype; 
     //your logic goes here and also can play here with your dataitem. 
     if (Double.TryParse(data.CollD.ToString(), out doubleValue)) 
     { 
      if (doubleValue < 0) 
       brush = new SolidColorBrush(Colors.Red); 
     }   
    } 
    return brush; 
} 
+0

我最終做了類似的事情,但保留「綁定路徑」爲「Content.Text」。謝謝! – vlad