我正在尝试使用MVVM创建极坐标图。径向轴是风速,径向角是风向。我可以创建径向圆(椭圆)和径向速度轴标签。对于角度线(如轮辐),我创建了一个自定义控件,它只是一个末尾带有文本块的线(给出角度轴值)。但是,我无法让我的程序设置此自定义控件的属性,因此您无法在画布上看到它们(虽然它们在那里,但默认长度为零,默认文本为空)?
好的,所以我的diagram.xaml如下:
<Grid>
<Grid.DataContext>
<local:DiagramViewModel x:Name="ViewModel" />
</Grid.DataContext>
<Viewbox x:Name="myView"
Stretch="Uniform"
StretchDirection="Both">
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Height="400" Width="400"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Right" Value="{Binding Right}"/>
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
<Setter Property="Canvas.Bottom" Value="{Binding Bottom}"/>
<Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:EllipseItem}">
<Ellipse Stroke="{Binding Stroke}"
StrokeThickness="{Binding StrokeThickness}"
StrokeDashArray="{Binding StrokeDashArray}"
Height="{Binding Height}"
Width="{Binding Width}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:GridLineItem}">
<View:GridLineComponent Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Length="{Binding Path=Length, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
GridHeight="{Binding Path=GridHeight, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
LineColour="{Binding Path=LineColour, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextColour="{Binding Path=TextColour, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
RenderTransform="{Binding RenderTransform}"
RenderTransformOrigin="{Binding RenderTransformOrigin}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:TextBlockItem}">
<TextBlock Text="{Binding Text}"
Foreground="{Binding Foreground}"
FontSize="{Binding FontSize}"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</Viewbox>
</Grid>
我的viewmodel(DiagramViewModel)以及其他内容包含以下创建这些行的方法:
private void CreateAngularLines(double originMargin)
{
IList<GridLineItem> angularLine = new List<GridLineItem>();
double increment , angularGridlineCount, angle, height, width;
if (this.minorAngularIncrement == null)
increment = (double)this.majorAngularIncrement;
else
increment = (double)this.minorAngularIncrement;
angularGridlineCount = 360 / increment;
height = 200;//half the length of the canvas
width = 200;
for (int i = 0; i < angularGridlineCount; i++)
{
angularLine.Add(new GridLineItem());
angle = i * increment;
if (angle == 0 || angle == 180)
angularLine[i].Text = angle.ToString("000");
else if (angle < 180)
angularLine[i].Text = "G" + angle.ToString("000");
else
angularLine[i].Text = "R" + (360 - angle).ToString("000");
angularLine[i].Length = height - originMargin;
angularLine[i].GridHeight = height;
angularLine[i].LineColour = this.LineColour;
angularLine[i].TextColour = this.TextColour;
angularLine[i].Left = width - 18;
angularLine[i].Top = 0;
angularLine[i].Right = width;
angularLine[i].Bottom = height;
angularLine[i].ZIndex = 1;
angularLine[i].RenderTransformOrigin = new Point(0.5, 1);
angularLine[i].RenderTransform = new RotateTransform(angle, 0, 0);
}
Points.Add(new CollectionContainer() { Collection = angularLine });
}
GridLineItem类是一个简单的holder类,包含以下内容:
public class GridLineItem
{
public GridLineItem()
{
this.RenderTransformOrigin = new Point(0.5, 1);
this.RenderTransform = new RotateTransform(0, 0, 0);
this.Left = double.NaN;
this.Right = double.NaN;
this.Top = double.NaN;
this.Bottom = double.NaN;
}
public Brush LineColour { get; set; }
public Brush TextColour { get; set; }
public string Text { get; set; }
public double Length { get; set; }
public double GridHeight { get; set; }
public Point RenderTransformOrigin { get; set; }
public Transform RenderTransform { get; set; }
public int ZIndex { get; set; }
public double Left { get; set; }
public double Right { get; set; }
public double Top { get; set; }
public double Bottom { get; set; }
}
现在这就是我认为我出错的地方。 GridlineComponent.xaml.cs文件包含以下内容:
public partial class GridLineComponent : UserControl, INotifyPropertyChanged
{
public GridLineComponent()
{
InitializeComponent();
this.DataContext = this;
}
public GridLineComponent(string text, double length, double gridHeight) : this()
{
this.Text = text;
this.Length = length;
this.GridHeight = gridHeight;
}
public Brush LineColour
{
get { return (Brush)GetValue(LineColourProperty); }
set
{
SetValue(LineColourProperty, value);
NotifyPropertyChanged("LineColour");
}
}
public Brush TextColour
{
get { return (Brush)GetValue(TextColourProperty); }
set
{
SetValue(TextColourProperty, value);
NotifyPropertyChanged("TextColour");
}
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set
{
if (value == null)
SetValue(TextProperty, "");
else
SetValue(TextProperty, value); //"\u00B0";
NotifyPropertyChanged("Text");
}
}
public double Length
{
get { return (double)GetValue(LengthProperty); }
set
{
SetValue(LengthProperty, value);
NotifyPropertyChanged("Length");
}
}
public double GridHeight
{
get { return (double)GetValue(GridHeightProperty); }
set
{
SetValue(GridHeightProperty, value);
NotifyPropertyChanged("GridHeight");
}
}
public static readonly DependencyProperty TextColourProperty =
DependencyProperty.Register(
"TextColour",
typeof(Brush),
typeof(GridLineComponent),
new PropertyMetadata(default(Brush), OnItemsPropertyChanged));
public static readonly DependencyProperty LineColourProperty =
DependencyProperty.Register(
"LineColour",
typeof(Brush),
typeof(GridLineComponent),
new PropertyMetadata(default(Brush), OnItemsPropertyChanged));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(
"Text",
typeof(string),
typeof(GridLineComponent),
new PropertyMetadata(default(string), OnItemsPropertyChanged));
public static readonly DependencyProperty LengthProperty =
DependencyProperty.Register(
"Length",
typeof(double),
typeof(GridLineComponent),
new PropertyMetadata(default(double), OnItemsPropertyChanged));
public static readonly DependencyProperty GridHeightProperty =
DependencyProperty.Register(
"GridHeight",
typeof(double),
typeof(GridLineComponent),
new PropertyMetadata(default(double), OnItemsPropertyChanged));
private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
GridLineComponent source = d as GridLineComponent;
// Do something...
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}
基本上这个GridLineComponent不遵循MVVM的规则。但我认为这是可以的,因为它是一种基本类型。它的xaml只是一个包含一行和一个TextBlock的网格。行的Y2和笔划属性绑定到xaml.cs(分别为Length和LineColour),文本块的前景和文本属性(分别为TextColour和Text)也是如此。
从我所看到的,这些线应该画,但不是。我认为它可能与依赖属性或由于空的OnItemsPropertyChanged处理程序有关。另外,当程序运行时,只访问GridlineComponent.xaml.cs的非参数构造函数(未设置属性)?