2009-11-10 6 views
2

У меня вопрос о динамическом позиционировании WPF.WPF Динамическое связывание X и Y Координаты

Я хочу разместить Elipses на экране, основанный на координатах X и Y, которые я сохранил в коллекции на C#.

Мне сообщили о возможности рисования в WPF, которую вы делаете с C#, используя Windows.Media и Windows.Shapes.

Теперь, что я на самом деле хочу сделать, это использовать эти пространства имен для рисования элипсов в первом случае в холсте, выполненном в C#, используя мой источник данных, который у меня есть в C#, чтобы расположить элипсы, используя координаты x и y ,

Теперь сложная часть меня смущает, что если данные в источнике данных изменяются по мере изменения данных в базе данных, я реализую какую-то рутину, которая каждые несколько секунд проверяет базу данных, отбрасывая назад любые данные, которые с момента последнего извлечения. Теперь я видел интерфейс IPropertyChanged, который я унаследую для своего класса, который я предоставляю как источник данных для страницы, поэтому, когда я извлекаю обновленный набор данных, я могу вызвать событие PropertyChanged, которое уведомит WPF о том, что источник данных изменился.

Как я могу связать elipses в пользовательском интерфейсе, когда я изначально выставлял их на C# некоторым элементам из источника данных, поэтому, когда источник данных изменил элипсы, автоматически изменился бы, если потребуется, чтобы отразить измененный источник данных до тех пор, пока идентификатор для каждой координаты x и y остались прежними. Так могу ли я привязываться к определенным строкам из коллекции для каждого elipse в моем холсте, когда я их выставляю?

Я даже не знаю, возможно ли связать источник данных с Canvas, внутри которого я могу использовать коллекцию, как мне нужно начинать, но я думал, что поставил бы этот вопрос там, если кто-то сделал что-то похожее поэтому у меня хорошая отправная точка.

Thanks Iffy.

ответ

0

Вы можете использовать преобразование перевода, чтобы расположить эллипсы по мере их создания.

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

Вы можете хранить эллипсы в словаре с идентификатором, поскольку они служат для быстрого и легкого извлечения.

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

Это своего рода старая школьная манера делать это, очень winforms. На самом деле нет необходимости создавать или возиться с базовыми формами, подобными этому в коде. – Egor

0

Вы можете сделать это в DataTemplate, если ваши объекты Ellipse представлены классом, и, возможно, появится в ItemsControl.

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

Вы бы choose between LayoutTransform and RenderTransform на основе панели, которая состоялась ваши объекты Ellipse.

Я также рекомендую рассмотреть статью Бэ Столнитца (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 инлайн можно связать с коллекцией на вашу ViewModel (лучший выбор), свойство зависимости от элемента управления или окон, установите ресурс из коды и т.д.

Ключевым моментом является то, что вы не должны выкладывать эллипсы в C#, если вам не обязательно. Предоставьте данные как своего рода список значимых объектов. Затем создайте шаблон данных, который определяет, как эти данные будут представлены. Предполагая, что вам не нужно выполнять какую-либо сложную обработку вашего объекта, чтобы получить соответствующие свойства эллипса, вы сможете сделать это без какого-либо кода или, самое большее, с несколькими преобразователями значений.

Это своего рода разделение пользовательского интерфейса, которое позволяет вам заниматься обновлением источника данных (бизнес-логикой) и отображением элементов (ui) отдельно.

Поэтому в основном идея:

  • Expose коллекции объектов - в моем примере это будет набором классов, отражающих структуру формы XML-элемент в списке. Это может быть сам бизнес-объект, или viewmodel - класс, который обертывает бизнес-объекты и предоставляет удобные связываемые свойства (в данном случае, положение и размер). Сама коллекция предпочтительнее будет ObservableCollection, так что пользовательский интерфейс уведомляется при добавлении или удалении объектов. Бросьте в него какие-то данные о времени разработки, если это возможно.
  • Привязать к коллекции, используя таблицы данных WPF, чтобы определить, как должен быть представлен элемент. В этом случае я использовал простой элемент ItemsControl с несколькими простыми шаблонами, но это может быть как можно сложнее
  • Изучите, как коллекция будет обновляться из исходного источника данных. Если вы правильно настроили предыдущие шаги, это, по сути, отдельная проблема.
Смежные вопросы