2009-11-10 200 views
2

我对WPF动态定位有一个问题。WPF动态绑定X和Y坐标

我想将Elipses放在屏幕上,基于X和Y坐标,我已经存储在C#集合中。

我已经意识到WPF中的绘图功能,您可以使用Windows.Media和Windows.Shapes从C#中进行绘图。

现在我真正想要做的就是使用这些命名空间在第一种情况下在画布中绘制elipses所有在C#中完成使用我的数据源,我在C#中使用X和Y坐标定位elipses 。

现在,令我困惑的复杂部分是如果数据源中的数据随着数据库中的数据更改而发生更改,我将实施某种例程,每隔几秒检查一次数据库,以便将数据自上次检索后发生了变化。现在我已经看到了IPropertyChanged接口,我将从我的类中接受我作为我的页面数据源公开的类,因此当我检索更新的数据集时,我可以调用PropertyChanged事件,它将通知WPF数据源已更改。

当我最初将它们从C#中放到数据源中的某些项目中时,我将如何绑定UI中的elipses,所以当数据源更改时,elipses会根据需要自动更改以反映更改的数据源,只要ID对于每个x和y坐标保持不变。那么我可以绑定到集合中的每个椭圆的特定行,当我设置它们时?

我甚至不知道是否有可能将数据源绑定到一个Canvas里面,我可以使用集合,因为我需要开始,但我想我会把这个问题放在那里,因为有人做了类似的事情所以我有一个很好的起点。

谢谢 Iffy。

回答

0

您可以使用转换变换来定位创建椭圆时的位置。

 TranslateTransform transform = new TranslateTransform(); 
     transform.X = X; 
     transform.Y = Y; 
     Ellipse ellipse = new Ellipse(); 
     ellipse.RenderTransform = transform; 
     ... 

您可以将椭圆存储在带有id的字典中,因为它们是快捷方便的检索关键。

 TranslateTransform transform = data[id].RenderTransform as TranslateTransform; 
     transform.X = newX; 
     transform.Y = newY; 
+0

这是一种旧式的做法,很winforms。真的没有必要在代码中创建或提取像这样的基本形状。 – Egor 2009-11-13 19:15:44

0

你可以,如果你的椭圆对象由一个类来表示,也许在ItemsControl显示DataTemplate内做到这一点。

<Ellipse> 
    <Ellipse.LayoutTransform> 
     <TranslateTransform X="{Binding XCoord}" 
          Y="{Binding YCoord}" /> 
    </Ellipse.LayoutTransform> 
</Ellipse> 

你会choose between LayoutTransform and RenderTransform基于持有你的椭圆对象的面板。

我还建议阅读Bea Stollnitz(ne&eacute; Costa)的一篇文章,其中展示了如何利用ListBox backed by a Canvas with DataBinding to produce offset objects。很酷。

1

建立在别人在这里所说的是一个完整的自包含的例子 - 你可以直接复制到kaxaml或xamlpad(或混合,但我认为在这种情况下,它必须进入一个用户控件的体或一个窗口),看看它是如何工作的。

取而代之的是使用rendertransform,我更喜欢使用画布并设置left和top属性,我只是觉得它更具可读性。或者,您可以使用网格并设置边距,但您需要某种类型的值转换器。

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 

<Grid.Resources> 

    <!-- This is our list of shapes, in this case an inline XML list --> 
    <XmlDataProvider x:Key="ShapeList"> 
    <x:XData> 
    <ObjectList xmlns=""> 
    <Shapes> 
     <shape height="30" width="30" x="50" y="50"/> 
     <shape height="30" width="40" x="100" y="100"/> 
     <shape height="30" width="50" x="150" y="150"/> 
     <shape height="30" width="60" x="200" y="200"/> 
     <shape height="30" width="70" x="250" y="350"/> 
    </Shapes> 
    </ObjectList> 
    </x:XData> 
    </XmlDataProvider> 
</Grid.Resources> 

<ItemsControl ItemsSource="{Binding Source={StaticResource ShapeList}, XPath=ObjectList/Shapes/*}"> 

    <!-- this template sets the panel as canvas for easy positioning --> 
    <ItemsControl.ItemsPanel> 
    <ItemsPanelTemplate> 
    <Canvas IsItemsHost="True"/> 
    </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 

    <!-- this template defines how each bound item is represented --> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
    <Border Width="{Binding [email protected]}" Height="{Binding [email protected]}"> 
    <Ellipse Fill="White" Stroke="Black" StrokeThickness="2"/> 
    </Border> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 

    <!-- This style positions each bound item's container --> 
    <ItemsControl.ItemContainerStyle> 
    <Style> 
    <Setter Property="Canvas.Left" Value="{Binding [email protected]}"/> 
    <Setter Property="Canvas.Top" Value="{Binding [email protected]}"/> 
    </Style> 
    </ItemsControl.ItemContainerStyle> 

</ItemsControl> 
</Grid> 

取而代之的结合可以绑定到你的视图模型(最佳选择),在你的控制或窗口依赖项属性集合的内联XML列表中,设置从代码隐藏的资源,等等。

关键是,除非你绝对必须,否则你不应该在C#中布局椭圆。提供数据作为某种有意义的对象列表。然后创建一个数据模板来定义数据如何表示。假设您不必对对象进行任何复杂的处理以获得相关的椭圆属性,则应该可以在不使用任何代码的情况下执行此操作,或者最多使用少数值转换器。

这是一种UI分离,允许您分别处理更新数据源(业务逻辑)和显示项目(ui)。

所以基本上的理念是:

  • 公开对象的集合 - 在我的例子,这将是类镜像列表中的形状XML元素的结构集合。这可以是业务对象本身,也可以是视图模型 - 一个包装业务对象并公开可方便绑定属性(在本例中为位置和大小)的类。该集合本身会优先为ObservableCollection,以便在添加或删除对象时通知UI。如果可能的话,将一些设计时间数据投入。
  • 绑定到集合,使用WPF数据模板来定义元素应该如何呈现。在这种情况下,我使用了简单的ItemsControl和几个简单的模板,但是这可以根据需要尽可能复杂。
  • 计算如何从原始数据源更新集合。如果你正确设置了前面的步骤,这本质上是一个单独的问题