我有一个Datagrid,其中一些列是DataGridTemplateColumn,如此
<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>
我的问题是当我选择一行时,我的自定义控件不像DataGridTextColumn那样改变它的前景色。
如何设置自定义控件或数据网格的样式以强制更改所有列
修改1 我的自定义对象。
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 :(得分:2)
您只需要每次TextBlock
或Foreground
更改内联颜色(内部FloatColor
)。困难的方法是在TextBox
- 属性和内联属性之间添加绑定。简单的方法是将属性更改的回调添加到依赖项属性,或者仅通过覆盖OnPropertyChanged
:
例如(说明使用OnPropertyChanged
更新控件):
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)
});
}
}
同样适用于FontFamily
和FontSize
。这样,只要UpdateTextBlock()
使用的任何属性更新 - 无论是通过样式还是触发器 - 控件都将知道它需要更新内部TextBlock
中的内联。
更新08/27
此外,更新您的Style
以设置{set}中的Foreground
和FloatColor
,同时使用MultiDataTrigger
来考虑行的所选状态和网格的焦点状态。
<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>