我有一个UserControl
,在XAML中引用如下:
<local:ColumnGraphRenderCtrl x:Name="graphCtrl" Grid.Column="1"
Height="Auto" Width="Auto"/>
有问题的UserControl
有几个矩形形状,它们显示正常。
然而,如果我指定Background
颜色,指定的颜色会阻碍矩形,并且只会显示颜色。例如:
<local:ColumnGraphRenderCtrl x:Name="graphCtrl" Background="Blue" Grid.Column="1"
Height="Auto" Width="Auto"/>
(如果我将颜色更改为&#34;透明&#34;,矩形确实可见。)
我还尝试使用ControlTemplate
作为UserControl
(作为Style
的一部分),但我得到了相同的结果(即阻止UserControl内容的背景颜色)
我在MSDN上查找了 Control.Background 属性,该属性提供了以下注释:
Background属性仅适用于a的静止状态 控制。控件的默认样式指定其外观 当控制状态发生变化时。例如,如果您设置了 Button上的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<NameValuePair> _dataPoints = null;
private List<Color> _columnColors = new List<Color>() { Colors.Blue, Colors.Red, Colors.Green };
public ColumnGraphRenderCtrl()
{
InitializeComponent();
}
public void SetData(ObservableCollection<NameValuePair> 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++;
}
}
}
}
}
答案 0 :(得分:4)
为了编写一个通过覆盖OnRender
方法进行渲染的自定义控件,您不应该从UserControl
甚至Control
派生,因为它们通过{ {1}},也使用ControlTemplate
画笔填充其区域。所有这些都是在他们的OnRender方法之外完成的,所以要覆盖它而不是调用基类&#39; OnRender没有帮助。
相反,派生自Background
或FrameworkElement
,声明一个UIElement
属性并在完成其余渲染之前用背景填充控件区域:
Background
您可以在MSDN上的Control Authoring Overview文章中找到更多信息。有一节关于派生自FrameworkElement。
答案 1 :(得分:1)
所以我对此的解决方案有效,但你必须摆弄宽度和高度。在用户控件中,我添加了一个视图框和一个统一的网格。
<UserControl x:Class="GraphingWithShapes.ColumnGraphRenderCtrl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Viewbox>
<UniformGrid x:Name="GraphGrid" />
</Viewbox>
</UserControl>
然后根据输入的数据设置它的宽度和高度。使列等于数据的计数。 (注意我没有像你那样改变图形颜色的逻辑)。然后我添加了一个Border(有一个边框和一个背景)并将其添加到unifrom网格中。 (代码在这里)
public void SetData(ObservableCollection<NameValuePair> 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);
}
当我在我的用户控件上添加背景颜色时,它现在可以正常工作。我希望这会有所帮助。
答案 2 :(得分:1)
如果使用Visual Studio的模板创建自定义控件,它将创建一个Generic.xaml文件,为控件提供ControlTemplate。
此模板中的默认设置使其从ControlTemplate复制Border的背景,这会导致背景(在自定义控件上无法复制地呈现)以过度绘制控件。
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Border Background="{TemplateBinding Background}">
要解决此问题,请从ControlTemplate中移除Border Background
,然后渲染背景填充矩形作为您在OnRender中绘制的第一个内容:
drawingContext.DrawRectangle(Background, null, new Rect(RenderSize));