【问题标题】:Canvas child does not shift position帆布孩子不移动位置
【发布时间】:2011-10-04 22:30:14
【问题描述】:

部落,

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

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

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

感谢您的帮助, -上午

有效的代码:

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); }
}
}

通用.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>

知道了!

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

一旦我们将相同的位置和大小属性应用到 TextBubble 本身 - 瞧,它就起作用了。

关键是: ((Control)canvas.GetDescendant()).GetDescendant().GetValue(Canvas.LeftProperty) 200.0

这表明网格确实设置了位置 - 但它的父级 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);
}

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

【问题讨论】:

  • 你在自定义控件的构造函数中试过了吗:this.DataContext = this;
  • 我确实尝试过 this.DataContext = this;不过没有帮助。
  • 这里不需要代码,你的控件模板可以完美处理——看我的回答。

标签: silverlight canvas custom-controls position


【解决方案1】:

这是可行的解决方案,我刚刚检查过。你仍然有两个选择: 1.在构造函数中设置DataContext,使用常规的Bindings 2. 不要设置 DataContext 并使用 RelativeSource 作为源(请参阅下面的 XAML)

Canvas.Left 和 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>

【讨论】:

  • FindAncestor 和 AncestorType 在 Silverlight 4.0 中显然不可用。感谢您的尝试。我将继续放弃这种方法,因为笨重的方法有效但很丑。
  • 奇怪的是 Text 和 Fill 属性可以工作并应用于文本块和椭圆。但直径和 X,Y 值不是。是否有某种“更新你的懒狗”命令来让画布自行更新?
猜你喜欢
  • 1970-01-01
  • 2020-05-08
  • 2012-11-05
  • 2021-09-10
  • 2023-04-07
  • 1970-01-01
  • 2012-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多