通过基本的 WPF 指导新手?(我不理解它.) [英] Coach a newbie through basic WPF? (I Do Not Grok It.)

查看:24
本文介绍了通过基本的 WPF 指导新手?(我不理解它.)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题正如其名.无论我多么努力、多么频繁地尝试理解 WPF,我都觉得我的头撞到了墙上.我喜欢 Winforms,一切都有意义.

Question is as it sounds. No matter how hard and how often I try to understand WPF, I feel like I'm hitting my head against a wall. I like Winforms, where everything makes sense.

举个例子,我正在尝试编写一个简单的应用程序,它允许我布置一堆二维路径(由折线表示)并拖动它们的顶点,并使顶点信息与演示者同步(也就是说,我想,一个 ViewModel)

As an example, I'm trying to write a simple app that will allow me to lay out a bunch of 2-D paths (represented by polylines) and drag their vertices around, and have the vertex information synchronised with a presenter (that is, I suppose, a ViewModel)

所以问题是这样的:

  • 使窗口将IEExtendedObjectPresenter的一个实例识别为数据源;
  • IExtendedObject的集合中,为每个IExtendedObject画一条折线;
  • 对于由集合 IExtendedObject.Points 表示的扩展对象中的每个顶点,在指定的坐标处放置一个折线顶点.
  • Make the window recognise an instance of IExtendedObjectPresenter as a data source;
  • From a collection of IExtendedObject, draw one polyline for each IExtendedObject;
  • For each vertex in the extended object, represented by the collection IExtendedObject.Points, place a polyline vertex at the specified co-ordinates.

IDE 在这里根本没有给我任何帮助.XAML 中可用的许多 属性对我来说没有任何意义.因为似乎隐含地做了这么多,所以没有明显的地方可以直接告诉窗口该做什么.

The IDE is giving me no help at all here. None of the many properties available in XAML sound meaningful to me. Because so much seems to be done implicitly, there is no obvious place to just tell the window what to do.

在我被安排并告知 RTFM 之前,我想再次强调,我已经研究了很多次 WPF 的基本概念.我对它的了解并不比它第一次发布时多.它似乎完全无法穿透.为一种行为给出的例子在任何情况下都不适用于一种甚至略有不同的行为,所以你又回到了原点.我希望重复和有针对性的考试可能会在某个时候点亮我的脑海.

Before I get slated and told to RTFM, I would like to re-emphasise that I have researched the basic concepts of WPF a great many times. I know no more about it than I did when it was first released. It seems totally inpenetrable. Examples given for one type of behaviour are not in any way applicable to an even slightly different kind of behaviour, so you're back to square one. I'm hoping that repetition and targeted exampes might switch a light on in my head at some point.

推荐答案

我很同情你.真正理解 WPF 需要很长时间,完成最简单的事情可能会非常令人沮丧.但是,深入研究专家们并不容易的问题只是自找麻烦.您需要处理更简单的任务并阅读大量代码,直到事情开始变得有意义.Donald Knuth 说在你做练习之前你并不真正了解这些材料.

I sympathize with you. Really understanding WPF takes a long time and it can be very frustrating to accomplish the simplest of things. But diving into a problem that is not easy for experts is only asking for trouble. You need to tackle simpler tasks and read a lot of code until things start to make sense. Donald Knuth says you don't really know the material until you do the exercises.

我解决了你的问题,我承认有很多先进的概念可以干净利落地做到这一点,而使用 MVVM 会使它变得更加困难.值得一提的是,这里是本着 MVVM 精神的零代码隐藏解决方案.

I solved your problem and I admit there are a lot of advance concepts in doing this cleanly and tacking on MVVM makes it that much harder. For what it's worth, here is a zero code-behind solution to your problem that is in the spirit of MVVM.

这是 XAML:

<Grid>
    <Grid.Resources>
        <local:PolylineCollection x:Key="sampleData">
            <local:Polyline>
                <local:Coordinate X="50" Y="50"/>
                <local:Coordinate X="100" Y="100"/>
                <local:Coordinate X="50" Y="150"/>
            </local:Polyline>
        </local:PolylineCollection>
    </Grid.Resources>
    <Grid DataContext="{StaticResource sampleData}">
        <ItemsControl ItemsSource="{Binding Segments}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Line X1="{Binding Start.X}" Y1="{Binding Start.Y}" X2="{Binding End.X}" Y2="{Binding End.Y}" Stroke="Black" StrokeThickness="2"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <ItemsControl ItemsSource="{Binding ControlPoints}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding X}"/>
                    <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Ellipse Margin="-10,-10,0,0" Width="20" Height="20" Stroke="DarkBlue" Fill="Transparent">
                        <i:Interaction.Behaviors>
                            <local:ControlPointBehavior/>
                        </i:Interaction.Behaviors>
                    </Ellipse>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Grid>

这里是支持类:

public class Coordinate : INotifyPropertyChanged
{
    private double x;
    private double y;

    public double X
    {
        get { return x; }
        set { x = value; OnPropertyChanged("X", "Point"); }
    }
    public double Y
    {
        get { return y; }
        set { y = value; OnPropertyChanged("Y", "Point"); }
    }
    public Point Point
    {
        get { return new Point(x, y); }
        set { x = value.X; y = value.Y; OnPropertyChanged("X", "Y", "Point"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(params string[] propertyNames)
    {
        foreach (var propertyName in propertyNames)
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class Polyline : List<Coordinate>
{
}

public class Segment
{
    public Coordinate Start { get; set; }
    public Coordinate End { get; set; }
}

public class PolylineCollection : List<Polyline>
{
    public IEnumerable<Segment> Segments
    {
        get
        {
            foreach (var polyline in this)
            {
                var last = polyline.FirstOrDefault();
                foreach (var coordinate in polyline.Skip(1))
                {
                    yield return new Segment { Start = last, End = coordinate };
                    last = coordinate;
                }
            }
        }
    }

    public IEnumerable<Coordinate> ControlPoints
    {
        get
        {
            foreach (var polyline in this)
            {
                foreach (var coordinate in polyline)
                    yield return coordinate;
            }
        }
    }
}

public class ControlPointBehavior : Behavior<FrameworkElement>
{
    private bool mouseDown;
    private Vector delta;

    protected override void OnAttached()
    {
        var canvas = AssociatedObject.Parent as Canvas;
        AssociatedObject.MouseLeftButtonDown += (s, e) =>
        {
            mouseDown = true;
            var mousePosition = e.GetPosition(canvas);
            var elementPosition = (AssociatedObject.DataContext as Coordinate).Point;
            delta = elementPosition - mousePosition;
            AssociatedObject.CaptureMouse();
        };
        AssociatedObject.MouseMove += (s, e) =>
        {
            if (!mouseDown) return;
            var mousePosition = e.GetPosition(canvas);
            var elementPosition = mousePosition + delta;
            (AssociatedObject.DataContext as Coordinate).Point = elementPosition;
        };
        AssociatedObject.MouseLeftButtonUp += (s, e) =>
        {
            mouseDown = false;
            AssociatedObject.ReleaseMouseCapture();
        };
    }
}

该解决方案使用了非常适合与 MVVM 实现交互的行为.

This solution uses behaviors, which are ideal for implementing interactivity with MVVM.

如果您不熟悉行为,请安装 Expression Blend 4 SDK 并添加以下命名空间:

If you are not familiar with behaviors, Install the Expression Blend 4 SDK and add this namespaces:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

并将 System.Windows.Interactivity 添加到您的项目中.

and add System.Windows.Interactivity to your project.

这篇关于通过基本的 WPF 指导新手?(我不理解它.)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆