画布的孩子不会转移位置

时间:2011-10-04 22:30:15

标签: silverlight canvas custom-controls position

部落,

我构建了一个Silverlight自定义控件TextBubble,它是一个网格内的椭圆和文本块。我正在通过代码按需将这些文本气泡添加到画布对象。当我这样做时,TextBubble的属性被设置,但是当对象出现在画布上时不会反映出来。

如果我手动构建相同的结构并将其添加到画布canvas.Children.Add(grid),则此子项将正确显示。

使用TextBubble,文本和椭圆显示但直径和X,Y未应用,气泡显示在画布的左上角。

感谢您的帮助, -AM

有效的代码:

Grid g = new Grid();
g.SetValue(Canvas.TopProperty, 100.0);
g.SetValue(Canvas.LeftProperty, 100.0);
Ellipse e = new Ellipse();
e.Width = 50;
e.Height = 50;
e.Fill = new SolidColorBrush(Colors.Green);
g.Children.Add(e);
TextBlock t = new TextBlock();
t.Text = "TEST";
t.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
t.VerticalAlignment = System.Windows.VerticalAlignment.Center;
g.Children.Add(t);
this.canvas.Children.Add(g);

不符合的代码:

TextBubble bubble = new TextBubble();
bubble.Text = "TEST";
bubble.Diameter = 50;
bubble.Fill = new SolidColorBrush(Colors.Green);
bubble.X = 100;
bubble.Y = 100;
canvas.Children.Add(bubble);

TextBubble对象:

public class TextBubble : Control {

public TextBubble() {
    this.DefaultStyleKey = typeof(TextBubble);
}

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text",
        typeof(string),
        typeof(TextBubble),
        new PropertyMetadata(new PropertyChangedCallback(OnTextChanged)));

public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register(
        "Diameter",
        typeof(int),
        typeof(TextBubble),
        new PropertyMetadata(new PropertyChangedCallback(OnDiameterChanged)));

public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
        "Fill",
        typeof(Brush),
        typeof(TextBubble),
        new PropertyMetadata(new PropertyChangedCallback(OnFillChanged)));

public static readonly DependencyProperty XCoordProperty = DependencyProperty.Register(
        "X",
        typeof(double),
        typeof(TextBubble),
        new PropertyMetadata(new PropertyChangedCallback(OnXCoordChanged)));

public static readonly DependencyProperty YCoordProperty = DependencyProperty.Register(
        "Y",
        typeof(double),
        typeof(TextBubble),
        new PropertyMetadata(new PropertyChangedCallback(OnYCoordChanged)));


public string Text {
    get { return (string)this.GetValue(TextProperty); }
    set { base.SetValue(TextProperty, value); }
}

public int Diameter {
    get { return (int)this.GetValue(DiameterProperty); }
    set { base.SetValue(DiameterProperty, value); }
}

public Brush Fill {
    get { return (Brush)this.GetValue(FillProperty); }
    set { base.SetValue(FillProperty, value); }
}

public double X {
    get { return (double)this.GetValue(XCoordProperty); }
    set { base.SetValue(XCoordProperty, value); }
}

public double Y {
    get { return (double)this.GetValue(YCoordProperty); }
    set { base.SetValue(YCoordProperty, value); }
}
}

Generic.xml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:X4S.Controls" >
<Style TargetType="local:TextBubble">
    <Setter Property="Text" Value="ABC" />
    <Setter Property="Diameter" Value="50" />
    <Setter Property="X" Value="100.0" />
    <Setter Property="Y" Value="100.0" />
    <Setter Property="Fill" Value="GhostWhite" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:TextBubble">
                <Grid x:Name="LayoutRoot" Canvas.Top="{TemplateBinding Y}" Canvas.Left="{TemplateBinding X}" >
                    <Ellipse Fill="{TemplateBinding Fill}" Width="{TemplateBinding Diameter}" Height="{TemplateBinding Diameter}"/>
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Text}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
</ResourceDictionary>

知道了!

当向画布子树添加新的自定义控件时,我们得到了包含grid-textblock-ellipse包的额外内容(TextBubble)。好吧,TextBubble对象从未设置过它的位置或大小。因此,即使文本和填充应用于内部控件,这些属性也不会受到TextBubble的位置或大小的影响。

一旦我们将相同的位置和大小属性应用于TextBubble本身 - 瞧它有效。

关键是:     ((对照)canvas.GetDescendant())。GetDescendant()。的GetValue(Canvas.LeftProperty)     200.0

这表明网格确实是DID的位置设置 - 但其父级TextBubble却没有。

修复:

private static void OnDiameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
    TextBubble textBubble = d as TextBubble;
    textBubble.Width = (int)e.NewValue;
    textBubble.Height = (int)e.NewValue;
}

private static void OnLeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
    TextBubble textBubble = d as TextBubble;
    textBubble.SetValue(Canvas.LeftProperty, e.NewValue);
}

private static void OnTopChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
    TextBubble textBubble = d as TextBubble;
    textBubble.SetValue(Canvas.TopProperty, e.NewValue);
}

可能有更好的方式(我会研究它),但这很有用。

1 个答案:

答案 0 :(得分:0)

这是工作解决方案,我刚检查过它。你还有两个选择: 1.在构造函数中设置DataContext并使用常规绑定 2.不要设置DataContext并使用RelativeSource作为源(参见下面的XAML)

Canvas.Left&amp; amp;应该为canvas的直接子节点设置Canvas.Top,它是local:TextBubble。

<Style TargetType="local:TextBubble">
        <Setter Property="Text" Value="ABC" />
        <Setter Property="Diameter" Value="50" />


        <Setter Property="Canvas.Top" 
                Value="{Binding Path=Y, RelativeSource={RelativeSource Self}}" />
        <Setter Property="Canvas.Left" 
                Value="{Binding Path=X, RelativeSource={RelativeSource Self}}" />

        <Setter Property="Fill" Value="GhostWhite" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TextBubble">
                    <Grid x:Name="LayoutRoot" >
                        <Ellipse Fill="{TemplateBinding Fill}" Width="{TemplateBinding Diameter}" Height="{TemplateBinding Diameter}"/>
                        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Text}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>