背景颜色会阻碍WPF UserControl内容

我有一个UserControl ,在XAML中引用如下:

  

有问题的UserControl有几个矩形形状,它们显示很好。

但是 ,如果我指定Background颜色,指定的颜色会阻碍矩形,并且只显示颜色。 例如:

  

(如果我将颜色更改为“透明”,则矩形会变得可见。)

我也尝试使用ControlTemplate作为UserControl (作为Style一部分),但我得到了相同的结果(即阻止UserControl内容的背景颜色)。

我在MSDN上查找了Control.Background属性,它提供了以下注释:

Background属性仅适用于控件的静止状态。 控件的默认样式指定控件状态更改时的外观。 例如,如果在Button上设置Background属性,则仅当未按下或禁用按钮时,该按钮才具有该值。 如果要创建具有更高级背景自定义的控件,则必须定义控件的样式。

此属性仅影响其模板使用Background属性作为参数的控件。 在其他控件上,此属性没有任何影响。

MSDN中的备注有什么意义,如何在不阻塞控件内容的情况下指定背景颜色?

编辑:内容控件(矩形)在代码隐藏中手动添加,如果这有所不同。

UserControl代码:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; namespace GraphingWithShapes { public partial class ColumnGraphRenderCtrl: UserControl { private ObservableCollection _dataPoints = null; private List _columnColors = new List() { Colors.Blue, Colors.Red, Colors.Green }; public ColumnGraphRenderCtrl() { InitializeComponent(); } public void SetData(ObservableCollection data) { _dataPoints = data; _dataPoints.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_dataPoints_CollectionChanged); InvalidateVisual(); } void _dataPoints_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { InvalidateVisual(); } public double GetLargestValue() { double value = 0; foreach (NameValuePair nvp in _dataPoints) { value = Math.Max(value, nvp.Value); } return value; } protected override void OnMouseDoubleClick(MouseButtonEventArgs e) { base.OnMouseDoubleClick(e); } protected override void OnRender(DrawingContext drawingContext) { if (_dataPoints != null) { double spaceToUseY = ActualHeight * 0.8; double spaceToUseX = ActualWidth * 0.8; double barWidth = spaceToUseX / _dataPoints.Count; double largestValue = GetLargestValue(); double unitHeight = spaceToUseY / largestValue; double bottom = ActualHeight * 0.9; double left = ActualWidth * 0.1; Brush fillBrush; Pen outlinePen = new Pen(Brushes.Black, 1); int nIndex = 0; Rect rect; double height; foreach (NameValuePair nvp in _dataPoints) { fillBrush = new SolidColorBrush(_columnColors[nIndex % _columnColors.Count]); height = (nvp.Value * unitHeight); rect = new Rect(left, bottom - height, barWidth, height); drawingContext.DrawRectangle(fillBrush, outlinePen, rect); left += rect.Width; nIndex++; } } } } } 

为了编写一个通过重写的OnRender方法进行渲染的自定义控件,您不应该从UserControl或甚至Control派生,因为它们通过ControlTemplate绘制自己, ControlTemplate也使用Background画笔填充它们的区域。 所有这些都是在他们的OnRender方法之外完成的,因此覆盖它并且不调用基类’OnRender将无济于事。

而是从FrameworkElementUIElement派生,声明Background属性并在执行其余渲染之前用背景填充控件区域:

 public class CustomControl : FrameworkElement { public static readonly DependencyProperty BackgroundProperty = Control.BackgroundProperty.AddOwner(typeof(CustomControl)); public Brush Background { get { return (Brush)GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); // just good practice drawingContext.DrawRectangle(Background, null, new Rect(RenderSize)); // your rendering code goes here... } } 

您可以在MSDN上的“ 控制创作概述”一文中找到更多信息。 有一节关于派生自FrameworkElement。

所以我的解决方案有效,但你必须摆弄宽度和高度。 在用户控件中,我添加了一个视图框和一个统一的网格。

      

然后根据输入的数据设置它的宽度和高度。使列等于数据的计数。 (注意我没有像你那样改变图形颜色的逻辑)。 然后我添加了一个Border(有一个边框和一个背景)并将其添加到unifrom网格中。 (代码在这里)

  public void SetData(ObservableCollection data) { _dataPoints = data; _dataPoints.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_dataPoints_CollectionChanged); GraphGrid.Columns = _dataPoints.Count; RebuildGraph(); InvalidateVisual(); } private void RebuildGraph() { GraphGrid.Children.Clear(); GraphGrid.Height = GetLargestValue(); GraphGrid.Width = _dataPoints.Count * 3; foreach (var item in _dataPoints) { AddGraphBar(item.Value); } } private void AddGraphBar(double value) { Border grid = new Border(); grid.BorderBrush = Brushes.Black; grid.BorderThickness = new Thickness(1); grid.Background = Brushes.Green; grid.VerticalAlignment = System.Windows.VerticalAlignment.Bottom; grid.Height = value; GraphGrid.Children.Add(grid); } 

当我在我的用户控件上添加背景颜色时,它现在可以正常工作。 我希望这有帮助。

如果使用Visual Studio的模板创建自定义控件,它将创建一个Generic.xaml文件,为控件提供ControlTemplate。

此模板中的默认设置使其从ControlTemplate复制Border的背景,这会导致背景(在您的自定义控件上无法复制地呈现)以过度绘制控件。

   

要解决此问题,请从ControlTemplate中删除Border Background ,并渲染背景填充矩形作为您在OnRender中绘制的第一个内容:

 drawingContext.DrawRectangle(Background, null, new Rect(RenderSize));