84423

WPF: Adding resource element to canvas and binding properties

Question:

I have programmed an application that draws elements in a canvas. These elements are Rectangles (but I used the Border class because I want to instert text in it). These elements represent objects (Tasks in my case).

I draw these elements in code behind like this:

foreach (var task in TasksList) { var rect = new Border(); rect.Background = (SolidColorBrush)(new BrushConverter().ConvertFrom("#0074D9")); rect.BorderBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom("#001f3f")); rect.BorderThickness = new Thickness(2); rect.Width = 60; rect.Height = 60; var t = new TextBlock { Text = task.Id.ToString(), Foreground = new SolidColorBrush(Colors.White), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; rect.Child = t; Canvas.SetLeft(rect, coordX); Canvas.SetTop(rect, coordY); Canvas.Children.Add(rect); }

Insted of designing the border (rect) in code behind. I would like to design it as a XAML resource and create instances of this resources in code behind. How can accomplish this? How can I use bindings in this case? For instance, in the xaml resource I need to define that the property ID of the task needs to be binded to the Text property of a TextBlock placed in the middle of the border. But later, in the code behind, how do I specify the DataContext of the properties defined in the xaml?

Hope you could guide me. Thanks

Answer1:

It's not really clear where the coordinate values come from, so I turned them into part of the TaskItem class. You can change this aspect however you may want.

In order to realize your code in WPF XAML, you need a visual representation of the item (DataTemplate) and a way to determine the item placement - I use a style for this aspect. The items will be placed on the canvas with an ItemsControl as suggested by Clemens.

The TaskItem is a plain class for this example. If you want to modify its contents after creation, you should better implement it with INotifyPropertyChanged.

public class TaskItem { public int Id { get; set; } public double CoordX { get; set; } public double CoordY { get; set; } }

The xaml, expecting the DataContext to contain a TasksList collection:

<Window.Resources> <DataTemplate x:Key="dtTaskItem" DataType="{x:Type local:TaskItem}"> <Border Background="#0074D9" BorderBrush="#001F3F" BorderThickness="2" Width="60" Height="60"> <TextBlock Text="{Binding Id}" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Border> </DataTemplate> <Style x:Key="canvasTaskItemStyle" TargetType="ContentPresenter"> <Setter Property="Canvas.Left" Value="{Binding CoordX}"/> <Setter Property="Canvas.Top" Value="{Binding CoordY}"/> </Style> </Window.Resources> <Grid x:Name="grid1"> <ItemsControl ItemsSource="{Binding TasksList}" ItemTemplate="{StaticResource dtTaskItem}" ItemContainerStyle="{StaticResource canvasTaskItemStyle}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </Grid>

And some example data to play with:

var tasksList = new List<TaskItem>() { new TaskItem { Id = 1, CoordX = 10, CoordY = 20 }, new TaskItem { Id = 2, CoordX = 60, CoordY = 160 }, new TaskItem { Id = 5, CoordX = 140, CoordY = 80 }, new TaskItem { Id = 3, CoordX = 50, CoordY = 50 }, new TaskItem { Id = 8, CoordX = 100, CoordY = 100 }, }; grid1.DataContext = new { TasksList = tasksList };

Sidenote: the resources could as well be placed inside a Grid.Resources section. The Window.Resources is just a default build I use when testing my answers to some WPF related stackoverflow question. The local:TaskItem expects the xaml namespace to be defined for the current project (In my case xmlns:local="clr-namespace:WpfTests_2").

Recommend

  • Primefaces CKEditor wrong URL encoding
  • objective-c protocol delegates
  • How to add action to a button?
  • error in adding google play services as reference library in eclipse
  • How do we specify the client area size of a form in design mode?
  • add scrollbar in qt window?
  • Mule ESB connecting to RabbitMQ
  • html/css: how to create a hexagonal image-placeholder
  • PHP Handling Namespace with SimpleXML
  • Angular2 emit event up to the DOM tree
  • Firebase, only get new children
  • How to convert WPF project so it can be used as a class library by a separate exe
  • LNK1104: cannot open file 'kernel32.lib'
  • Android Lock Screen C# .NET Replica
  • Invert string in Rust
  • Less Conflicting Session Manager for Zope 2
  • In Java, how can I construct a File from a resource?
  • WP8.1 AppBarButton holding event
  • Can I programmatically choose the Android layout folder?
  • How to disable all widgets inside Panel or inside Composite?
  • calculate gradient output for Theta update rule
  • JBoss External Properties Files in Classpath
  • how to display data from 1st point on words on y axis for line chart in d3.js
  • Repeat a vertical line on every page in Report Builder / SSRS
  • Change JButton Shape while respecting Look And Feel
  • Launch Runnable Jar from Web Start
  • recyclerView does not call the onBindViewHolder when scroll in the view
  • Controls, properties, events and timers running in design time
  • Arrow is showed instead of the material design version hamburger icon. Why doesn't syncState in
  • In LanguageTool, how do you create a dictionary and use it for spell checking?
  • jquery mobile loadPage not working
  • Comma separated Values
  • Error creating VM instance in Google Compute Engine
  • Hits per day in Google Big Query
  • Angular 2 constructor injection vs direct access
  • how does django model after text[] in postgresql [duplicate]
  • Java static initializers and reflection
  • Can Visual Studio XAML designer handle font family names with spaces as a resource?
  • Android Google Maps API OnLocationChanged only called once
  • UserPrincipal.Current returns apppool on IIS