[英]Background color obstructs WPF UserControl content
我有一個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"/>
(如果我將顏色更改為“透明”,則矩形將變為可見。)
我還嘗試將ControlTemplate
用於UserControl
(作為Style
一部分),但是得到了相同的結果(即,背景色阻塞了UserControl的內容)。
我在MSDN上查詢了Control.Background屬性,該屬性提供了以下說明:
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<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++;
}
}
}
}
}
為了編寫一個通過重寫的OnRender
方法進行渲染的自定義控件,您不應該從UserControl
甚至Control
派生出來,因為它們通過ControlTemplate
繪制,而后者也用Background
畫筆填充了它們的區域。 所有這些操作都是在OnRender方法之外完成的,因此重寫它而不調用基類的OnRender將無濟於事。
取而代之的是,從FrameworkElement
或UIElement
派生,聲明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派生。
因此,我的解決方案有效,但您必須擺弄寬度和高度。 在用戶控件中,我添加了一個視圖框和一個統一的網格。
<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);
}
當我在用戶控件上放置背景色后,它現在可以使用了。 我希望這有幫助。
如果使用Visual Studio的模板創建自定義控件,它將創建Generic.xaml文件,該文件為控件提供ControlTemplate。
此模板中的默認設置使它從ControlTemplate復制邊框的背景,這導致背景(在自定義控件的頂部莫名其妙地呈現)背景過度繪制了控件。
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Border Background="{TemplateBinding Background}">
若要解決此問題,請從ControlTemplate中刪除“ Border Background
”,並渲染背景填充矩形作為您在OnRender中繪制的第一件事:
drawingContext.DrawRectangle(Background, null, new Rect(RenderSize));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.