2017-08-26 3 views
0

J'ai un Datagrid où certaines colonnes sont DataGridTemplateColumn comme celui-ciXAML Set Premier plan pour CustomControl lorsque la ligne est sélectionnée

<DataGridTemplateColumn 
    Width="1.5*" 
    Header="{x:Static lang:Labels.GENERAL_ValorTotal}"> 
    <DataGridTemplateColumn.CellTemplate> 
     <DataTemplate> 
      <sty:DecimalTextBox 
       Text="{Binding Valor,StringFormat=\{0:c3\}}" 
       IsReadOnly="True" 
       Style="{StaticResource DecimalTextBoxGridStyle}"/> 
     </DataTemplate> 
    </DataGridTemplateColumn.CellTemplate> 
</DataGridTemplateColumn> 

enter image description here

Mon problème est lorsque je sélectionne une ligne, mon contrôle personnalisé ne fonctionne pas changez la couleur de premier plan comme le fait DataGridTextColumn.

Comment puis-je faire pour mon style de contrôle personnalisé ou mon DataGrid pour forcer toutes les colonnes à changer

Modifier 1 Mon objet personnalisé.

public class DecimalTextBox : TextBox 
{ 

    #region Float Color 
    public static readonly DependencyProperty FloatColorProperty = 
     DependencyProperty.Register("FloatColor", typeof(Color), typeof(DecimalTextBox), new FrameworkPropertyMetadata(Colors.Red)); 
    public Color FloatColor 
    { 
     get { return (Color)GetValue(FloatColorProperty); } 
     set { SetValue(FloatColorProperty, value); } 
    } 
    #endregion 

    #region Show Zero value 
    public bool ShowZeroValue 
    { 
     get { return (bool)GetValue(ShowZeroValueProperty); } 
     set { SetValue(ShowZeroValueProperty, value); } 
    } 
    // Using a DependencyProperty as the backing store for ShowZeroValue. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ShowZeroValueProperty = 
     DependencyProperty.Register("ShowZeroValue", typeof(bool), typeof(DecimalTextBox), new PropertyMetadata(true)); 
    #endregion 

    protected TextBlock _textBlock; 
    protected FrameworkElement _textBoxView; 

    public DecimalTextBox() 
    { 
     _textBlock = new TextBlock() { Margin = new Thickness(1, 0, 0, 0) }; 
     Loaded += ExTextBox_Loaded; 
    } 

    private void ExTextBox_Loaded(object sender, RoutedEventArgs e) 
    { 
     Loaded -= ExTextBox_Loaded; 

     // hide the original drawing visuals, by setting opacity on their parent 
     var visual = this.GetChildOfType<DrawingVisual>(); 

     if (visual != null) 
     { 
      _textBoxView = (FrameworkElement)visual.Parent; 
      _textBoxView.Opacity = 0; 

      // add textblock to do the text drawing for us 
      var grid = this.GetChildOfType<Grid>(); 
      if (grid.Children.Count >= 2) 
       grid.Children.Insert(1, _textBlock); 
      else 
       grid.Children.Add(_textBlock); 
     } 
    } 

    protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) 
    { 
     base.OnLostKeyboardFocus(e); 

     _textBoxView.Opacity = 0; 
     _textBlock.Visibility = Visibility.Visible; 
     MustShowValue(); 
    } 

    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) 
    { 
     base.OnGotKeyboardFocus(e); 

     _textBoxView.Opacity = 1; 
     _textBlock.Visibility = Visibility.Collapsed; 
    } 

    private bool MustShowValue() 
    { 
     bool show = true; 
     if (!ShowZeroValue && Text == "0") 
     { 
      show = false; 
      _textBlock.Inlines.Clear(); 
      _textBlock.Inlines.Add(new Run 
      { 
       Text = string.Empty, 
       FontFamily = FontFamily, 
       FontSize = FontSize, 
       Foreground = Foreground 
      }); 

      _textBlock.Inlines.Add(new Run 
      { 
       Text = string.Empty, 
       FontFamily = FontFamily, 
       TextDecorations = System.Windows.TextDecorations.Underline, 
       BaselineAlignment = BaselineAlignment.TextTop, 
       FontSize = FontSize * 5/6, 
       Foreground = new SolidColorBrush(FloatColor) 
      }); 
     } 
     return show; 
    } 

    protected override void OnTextChanged(TextChangedEventArgs e) 
    { 
     base.OnTextChanged(e); 

     if (MustShowValue()) 
     { 
      // making sure text on TextBlock is updated as per TextBox 
      var dotPos = Text.IndexOf('.'); 
      var textPart1 = dotPos == -1 ? Text : Text.Substring(0, dotPos + 1); 
      var textPart2 = (dotPos == -1 || dotPos >= (Text.Length - 1)) ? null : Text.Substring(dotPos + 1); 

      _textBlock.Inlines.Clear(); 
      _textBlock.Inlines.Add(new Run 
      { 
       Text = textPart1, 
       FontFamily = FontFamily, 
       FontSize = FontSize, 
       Foreground = Foreground 
      }); 

      if (textPart2 != null) 
       _textBlock.Inlines.Add(new Run 
       { 
        Text = textPart2, 
        FontFamily = FontFamily, 
        TextDecorations = System.Windows.TextDecorations.Underline, 
        BaselineAlignment = BaselineAlignment.TextTop, 
        FontSize = FontSize * 5/6, 
        Foreground = new SolidColorBrush(FloatColor) 
       }); 
     } 
    } 
} 

public static class HelperExtensions 
{ 
    public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj == null) return null; 

     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
     { 
      var child = VisualTreeHelper.GetChild(depObj, i); 

      var result = (child as T) ?? GetChildOfType<T>(child); 
      if (result != null) return result; 
     } 
     return null; 
    } 
} 


<Style x:Key="DecimalTextBoxGridStyle" TargetType="{x:Type local:DecimalTextBox}"> 
    <Setter Property="TextAlignment" Value="Right"/> 
    <Setter Property="FloatColor" Value="Black"/> 
    <Setter Property="BorderBrush" Value="Transparent"/> 
    <Setter Property="Background" Value="Transparent"/> 
    <Setter Property="ShowZeroValue" Value="False"/> 
    <Style.Triggers> 
     <!--<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" Value="True"> 
      <Setter Property="Foreground" Value="White"/> 
     </DataTrigger>--> 
    </Style.Triggers> 
</Style> 
+0

Pourriez-vous ajouter du code de 'DecimalTextBox' et' DecimalTextBoxGridStyle'? – Fruchtzwerg

+0

@Fruchtzwerg Tks pour votre intérêt. Code personnalisé publié. –

Répondre

2

Vous avez juste besoin de mettre à jour la ligne (s) couleur (en interne TextBlock) tous les temps Foreground ou FloatColor changements. Le plus difficile serait d'ajouter une ou plusieurs liaisons entre les propriétés TextBox et les propriétés en ligne. Le moyen facile serait soit ajouter la propriété a changé callbacks à la dépendance des biens ou tout simplement en remplaçant OnPropertyChanged:

Par exemple (illustre l'utilisation de OnPropertyChanged pour garder le contrôle mis à jour):

protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) 
{ 
    base.OnPropertyChanged(e); 

    if (e.Property == ForegroundProperty || e.Property == FloatColorProperty) 
     UpdateTextBlock(); //updates the text-block inlines 
} 

protected override void OnTextChanged(TextChangedEventArgs e) 
{ 
    base.OnTextChanged(e); 
    UpdateTextBlock(); // this can be merged to OnPropertyChanged (as text is also dependency property) 
} 

// new extracted method from OnTextChanged 
private void UpdateTextBlock() 
{ 
    if (MustShowValue()) 
    { 
     // making sure text on TextBlock is updated as per TextBox 
     var dotPos = Text.IndexOf('.'); 
     var textPart1 = dotPos == -1 ? Text : Text.Substring(0, dotPos + 1); 
     var textPart2 = (dotPos == -1 || dotPos >= (Text.Length - 1)) ? null : Text.Substring(dotPos + 1); 

     _textBlock.Inlines.Clear(); 
     _textBlock.Inlines.Add(new Run 
     { 
      Text = textPart1, 
      FontFamily = FontFamily, 
      FontSize = FontSize, 
      Foreground = Foreground 
     }); 

     if (textPart2 != null) 
      _textBlock.Inlines.Add(new Run 
      { 
       Text = textPart2, 
       FontFamily = FontFamily, 
       TextDecorations = System.Windows.TextDecorations.Underline, 
       BaselineAlignment = BaselineAlignment.TextTop, 
       FontSize = FontSize * 5/6, 
       Foreground = new SolidColorBrush(FloatColor) 
      }); 
    } 
} 

En va de même pour FontFamily et FontSize aussi. De cette façon, chaque fois qu'une propriété, que UpdateTextBlock() utilise, est mise à jour - que ce soit par le biais de style ou de déclencheurs - le contrôle saura qu'il doit mettre à jour le (s) inline (s) interne (s) TextBlock.

Mise à jour 08/27

Aussi, mettez à jour votre Style pour définir Foreground et FloatColor dans setters, tout en utilisant un MultiDataTrigger pour tenir compte de l'état sélectionné et de l'état ciblé de la grille des deux lignes.

<Style x:Key="DecimalTextBoxGridStyle" TargetType="{x:Type local:DecimalTextBox}"> 
    <Setter Property="TextAlignment" Value="Right"/> 
    <Setter Property="Foreground" Value="Black"/> 
    <Setter Property="FloatColor" Value="Black"/> 
    <Setter Property="BorderBrush" Value="Transparent"/> 
    <Setter Property="Background" Value="Transparent"/> 
    <Setter Property="ShowZeroValue" Value="False"/> 
    <Style.Triggers> 
     <MultiDataTrigger> 
      <MultiDataTrigger.Conditions> 
       <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}}" Value="True" /> 
       <Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=IsKeyboardFocusWithin}" Value="True" /> 
      </MultiDataTrigger.Conditions> 
      <MultiDataTrigger.Setters> 
       <Setter Property="Foreground" Value="White"/> 
       <Setter Property="FloatColor" Value="White"/> 
      </MultiDataTrigger.Setters> 
     </MultiDataTrigger> 
    </Style.Triggers> 
</Style> 
+0

Merci de votre aide. Je vais y jeter un coup d'œil. –

+0

Cela fonctionne très bien, la seule chose est que je dois définir les déclencheurs dans le style pour les deux propriétés ForeGround et FloatColors, pour Row sélectionné même et pour LostFocus sur DataGrid –

+0

Salut Juan, si je comprends bien votre question? - vous ne voulez pas deux couleurs différentes pour Foreground et FloatColor? Ensuite, vous pouvez simplement supprimer le besoin de FloatColor et Foreground pour les deux en ligne (s). Aussi, je ne crois pas que vous ayez besoin de 'MustShowValue()' dans lostfocus – Ada