WPF Canvas Binding - c#

I'm rather new to WPF, so maybe this is a simple question. I have a class that derives from Canvas, let's call it MyCanvas. And I have a class, MyClass, that has a property of type MyCanvas. In XAML, I built a TabControl, so each TabItem binds to a MyClass object. Now, in the Content of every tab I want to display MyObject.MyCanvas.
How should I do that?
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<myCanvas:MyCanvas Focusable="true" Margin="10" >
<Binding Path="Canvas"></Binding>
</myCanvas:MyCanvas>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>

You should use ContentPresenter
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<ContentPresenter Content="{Binding MyCanvas}" Focusable="true" Margin="10" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>

Try using ContentPresenter and binding the contents to the property you want. If the property is a descendent of Canvas, this should result in it simply displaying that content. If the property was of another type, it would attempt to use a DataTemplate to render it.

Related

Bind view model to content control/presenter

on uwp, I want to make a hamburger menu with custom icon in xaml. from the lunch scheduler sample from MS, I try to bind a viewmodel property to a content element in a view like :
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="viewmodels:MenuItem">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{x:Bind Icon2}" />
where Icon is a property like
Icon2 = Application.Current.Resources["BookIcon"],
which works and retreive a viewbox containing a canvas
but I got an exception "Value does not fall within the expected range."
Did some know if it's possible like in WPF ??
nb : if i put the canvas directly in the contentcontrol, it works. perhaps the binding does not accept anything else than string
i found a solution, convert the viewbox to DataTemplate and bind to ContentTemplate
<DataTemplate x:Key="BookIcon">
<Viewbox Width="48" Height="48">
<Canvas Width="24" Height="24">
<Path Data/>
</Canvas>
</Viewbox>
</DataTemplate>
and
<ContentControl ContentTemplate="{x:Bind Icon2}"/>
any other solution is welcome

Why would you use DataTemplate in a ListView?

could someone please explain to me what is the difference if I use
DataTemplate inside the ListView in XAML?
I have used ListView to display the content from my ObservableCollection without using DataTemplate and with DataTemplate it seems to look exactly the same?
Why then would I want to use Data Template? I would like to see a simple explanation/example.
DataTemplate is used to show data in ways beyond a simple text block. Sure doing this:
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
Doesn't buy you much. But it allows you to do stuff like this:
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding ImagePath}"/>
<TextBlock Text="{Caption}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
Which is pretty cool! You can put anything inside the template, so it makes ItemsControl (and its derivatives) some of the most powerful classes in WPF.
Please take a look at #HighCore's answer here WPF MVVM Why use ContentControl + DataTemplate Views rather than straight XAML Window Views?.
<Window x:Class="MyViews.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
xmlns:viewmodel="clr-namespace:Project.ViewModel"
DataContext="{Binding Main, Source={StaticResource Locator}}"
Title="{Binding Title, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}" Width="{Binding Width, Mode=TwoWay}" Left="{Binding Left, Mode=TwoWay}" Top="{Binding Top, Mode=TwoWay}" WindowStartupLocation="CenterScreen">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type viewmodel:OtherViewModel1}">
<ContentPresenter Content="{Binding Path=Text}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type viewmodel:OtherViewModel2}">
<view:ConnectivityLED />
</DataTemplate>
</Window.Resources>
So you can see Mainwindow is talking to more than 1 viewmodel, Main is its own view model which is its datacontext and it also has reference to otherviewmodel1 and otherviewmodel2. Hope this helps, Cheers!

Hide last item in a ItemsControl

I've a ItemsControl that I bind to my viewmodel, but inside the datatemplate I also have an image. I want that image to be visible as long as it's not the last item in the list, then it should be hidden (it's an arrow that point down to the next control).
The xaml look like this:
<ItemsControl ItemsSource="{Binding PageContainers}" x:Name="Items">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<controls:DesignControl DataContext="{Binding}" MouseDown="UIElement_OnMouseDown" MouseUp="UIElement_OnMouseUp" MouseMove="UIElement_OnMouseMove"/>
<Image Source="/Resources/Images/arrow.png" Height="16" Width="16" Margin="0,10,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So is there any easy to check if the Image/Stackpanel is last in the list? I guess I could subscribe to some event and do it in the code behind, but I guess it's cleaner if I could do it inside the xaml.
You're binding to PageContainers which I assume to be a collection. Can the type of that collection be extended to include an IsLast property?
If it can, you can bind the visibility to that.

How to create a DataTemplate with a StackPanel of a variable number of StackPanels

I am trying to create a DataTamplate which should contain a StackPanel with a certain number of StackPanels.
<DataTemplate x:Key="DataTemplate">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Rectangle Fill="Aqua" Margin="2" Height="100" Width="50" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</StackPanel>
</StackPanel>
</DataTemplate>
The code snippet above is just for a better understanding of my desired result, as the elements in the imbricated StackPanel will be binded.
This generates the following error message:
VisualTree of ItemsPanelTemplate must be a single element.
Any alternatives that could work?
You should ItemsControl with ItemsSource bound to your source list. In ItemsControl.ItemsPanel you can set which panel you want to use for items. In your case you should use StackPanel with Orientation=Vertical as ItemsPanel. See first sample here. But vertical StackPanel is already default ItemsPanel so you can omit it.
Inner StackPanel should be specified as ItemTemplate in your ItemsControl.
Your XAML should look like this:
<ItemsControl ItemsSource="...">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- properties of your object should go here -->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

WPF Listbox : How to bind data?

I have a listBox and add data to it like so:
for (int x = 0; x < Orchestrator.Instance.getTopicCount(); x++)
{
listTopics.Items.Add(Orchestrator.Instance.getTopic(x));
}
But I need to be able to do things like have text wrapping and divider lines, so I would like to do it the XAML.
Microsoft shows this:
<TextBlock Width="248" Height="24"
Text="{Binding ElementName=lbColor, Path=SelectedItem.Content,
Mode=OneWay}"
x:Name="tbSelectedColor"
Background="{Binding ElementName=lbColor, Path=SelectedItem.Content,
Mode=OneWay}"/>
But I don't really understand it. Here is my XAML:
<ListBox Height="261" HorizontalAlignment="Left" Margin="352,38,0,0" Name="listContent" VerticalAlignment="Top" Width="391" Grid.Column="1" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" MaxWidth="391" ScrollViewer.HorizontalScrollBarVisibility="Disabled"/>
How am I able to achieve what I want? (Divider lines, text wrapping so I don't have to scroll horizontally, and data binding)
To specify the layout of each item, there are two different things you can change: the ItemContainerStyle, which provides the ControlTemplate used for each ListBoxItem, or the ItemTemplate, which provides the DataTemplate that is used to render each data item. The ItemTemplate is simpler to use if you're just getting started and haven't gotten the hang of ControlTemplates yet.
To get your text to wrap, there are two key things to do. Turn off the default horizontal scrolling of ListBox (which you got already), and set the TextWrapping property of your TextBlock to Wrap. To get to the TextBlock you need to define it in your ItemTemplate. Here's a simple example of the template declared inline, though you could also pull it out as a Resource. For the dividing line I used the simplest approach of a Border with only a bottom black line.
<ListBox x:Name="listContent" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="Black">
<TextBlock Text="{Binding}" TextWrapping="Wrap"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
It seems that you will have to ascend the rather steep learning curve for how to use databinding in WPF first. Thereafter you should learn about DataTemplates and ItemTemplates to get the dividers and so forth.
Try this to get you started
A book I can heartily recommend is WPF in Action from Manning.
You need to define the ItemTemplate of your ListBox.
In your resources, add this:
<DataTemplate x:Key="myItemTemplate" TargetType="ListBoxItem">
<TextBlock Text="{Binding}"/>
</DataTemplate>
Supposing that your getTopic method returns a string, otherwise use {Binding MyTopicProperty} where MyTopicProperty is a property in your Topic class. Customize the TextBlock as you need.
Then use your ListBox like this:
<ListBox ItemTemplate="{StaticResource myItemTemplate"/>
here is an example how to bind listbox with RSS feed with DataTemplate:
<UserControl.Resources>
<XmlDataProvider x:Key ="DataRSS" XPath="//item" Source="http://rss.feedsportal.com/c/629/f/502199/index.rss">< /XmlDataProvider>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<ListBox ItemsSource="{Binding Source={StaticResource DataRSS}}" Height="516" Margin="0,0,32,0" Background="{x:Null}" BorderBrush="#FF627DAE">
<ListBox.ItemTemplate >
<DataTemplate >
<Grid Width="400" Height="100" >
<Image Source="{Binding XPath=enclosure/#url}" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" />
<TextBlock TextWrapping="Wrap" Text="{Binding XPath=title}" FontWeight="Bold" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</grid>

Categories