【问题标题】:Databound Triangle Creation?创建数据绑定三角形?
【发布时间】:2011-11-08 18:46:43
【问题描述】:

我需要根据提供的大小创建多个形状(所有形状都具有相同的高度/宽度),并将它们的大小数据绑定到数据上下文中提供的属性。

大多数形状都很简单:圆形(有高度/宽度限制的椭圆)、方形(有高度/宽度限制的矩形)、菱形(与方形相同,然后使用 RotateTransform)、+(两条线)、X (两行)。

但我试图弄清楚如何为三角形做这件事,但我无法弄清楚。它需要是一个填充的对象,所以我不能只用三行来完成。

但我所见过的所有方法(带有PathPolygon)最终都会采用Point 对象(StartPointEndPoint 等)。而且您不能绑定到Point 对象的XY 值。

我错过了什么吗?还是我需要编写自己的自定义形状或其他东西?

编辑:增加一点清晰度……我创建的三角形类型并不重要。它可以是等边的或等腰的。我的目标是等腰,这样它就有一个具有数据绑定宽度的底,三角形的顶部“尖端”将位于数据绑定宽度的中点和 Y = 0。为了简单起见,这只是一个优化

【问题讨论】:

  • 你是对的,一个矩形不能仅仅通过它的大小来描述。你在处理什么样的矩形?它们不是等腰的吗?
  • @Dmitry - 我假设你的意思是三角形,而不是矩形。我添加了一些附加信息,以说明我要使用哪种三角形。
  • 好吧,如果你的三角形是等腰的(这就够了),它们可以很容易地用一个矩形来描述,它们适合。换句话说,知道三角形适合的矩形以及三角形的事实是等腰线我总是可以准确地说出三角形是什么。:) 所以,你可以坚持你的尺寸并编写一个简单的行为来计算你的 Xs 和 Ys。
  • 嗯,对。但我的问题是找到一个 WPF 构造,它可以根据给定的高度/宽度对等腰三角形进行数据绑定。 @Erno 下面的答案可能是最简单的方法,但这意味着我需要修改我的视图模型,我试图避免这样做(从技术上讲,我不拥有它)。
  • 蒂姆,行为不就是这样做的机制吗?您需要创建一个路径并附加一个行为,因此它如下所示: 看起来很漂亮,隐藏在 PathBehavior.ShapeType 实现中的复杂性。

标签: wpf data-binding shapes


【解决方案1】:

行为类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media;

namespace WpfApplication1
{
    public enum ShapeType
    {
        Rectangle,
        Isosceles,
        Ellipse,
        Dice,
        Hexagon
    }

    public class PathControl
    {
        public static readonly DependencyProperty ShapeTypeProperty =
            DependencyProperty.RegisterAttached("ShapeType",
            typeof(ShapeType?),
            typeof(DependencyObject),
            new PropertyMetadata(null, 
                new PropertyChangedCallback((sender, args) => 
                { 
                    Path path = sender as Path;
                    ShapeType? shapeType = (ShapeType?)args.NewValue;

                    //todo: use a WeakEvent
                    path.SizeChanged += 
                        (pathSender, pathArgs) => 
                        {
                            PathControl.InvalidatePath((Path)sender, shapeType);
                        };

                })));


        private static void InvalidatePath(Path path, ShapeType? shapeType)
        {
            if (path != null
                && shapeType.HasValue)
            {
                string source = null;

                double netWidth = path.Width - 2 * path.StrokeThickness,
                       netHeight = path.Height - 2 * path.StrokeThickness;

                if (shapeType == ShapeType.Rectangle)
                {
                    source = string.Format("M0,0 h{0} v{1} h-{0} z",
                        new object[2]
                        {
                            netWidth,
                            netHeight
                        });
                }
                else if (shapeType == ShapeType.Isosceles)
                {
                    source = string.Format("M0,{1} l{0},-{1} {0},{1} z",
                        new object[2]
                        {
                            netWidth / 2,
                            netHeight
                        });
                }
                else
                {
                    throw new NotImplementedException(shapeType.ToString());
                }

                path.Data = Geometry.Parse(source);
            }
        }

        public static void SetShapeType(DependencyObject o, ShapeType e)
        {
            o.SetValue(PathControl.ShapeTypeProperty, e);
        }

        public static ShapeType? GetShapeType(DependencyObject o)
        {
            return (ShapeType)o.GetValue(PathControl.ShapeTypeProperty);
        }
    }
}

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:local="clr-namespace:WpfApplication1">
    <Grid>
        <Path Width="100" Height="100" Stroke="Green" StrokeThickness="2" Fill="Yellow"
              local:PathControl.ShapeType="Isosceles">
            <Path.RenderTransform>
                <RotateTransform Angle="90"></RotateTransform>
            </Path.RenderTransform>
        </Path>
    </Grid>
</Window>

【讨论】:

  • 我希望我能给你一个+2。我什至从未想过我可以将我的几何构造成这样的字符串。这是一个非常有创意的解决方案,因此我将其标记为答案。
【解决方案2】:

绑定到点是最好/唯一的方法。无法绑定 Point 的 X 和 X 属性,因为它们不会引发 PropertyChanged 事件。 Point 是一个结构体,结构体应该是只读的。

PointCollection 类引发正确的事件,以便您可以绑定到它。这允许您通过替换点来修改点的集合来操纵三角形。不要更改点,而是替换它们,以便引发适当的事件。

【讨论】:

  • 我想知道这是否是我需要走的路线。不幸的是,我不“拥有”视图模型,所以我只有要绑定的高度/宽度属性。我想我可能需要研究我是否可以拥有该类并添加一些新属性来绑定。
  • 您首先必须确定是否有可以绑定的属性或其他允许您更新 View/ViewModel 的更改事件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-17
  • 2020-01-10
  • 1970-01-01
  • 1970-01-01
  • 2019-10-15
  • 1970-01-01
相关资源
最近更新 更多