How to reuse contents in wpf/mvvm - wpf

I have a UI that displays a pattern of "first name/last name". So I thought I would reuse the same template. But I am facing some issues getting the binding right.
Note:-
PrimaryContactDataContext is nothing but a class, with a property named "value" which implements the *INotifyPropertyChanged" interface.
<StackPanel>
<ContentControl DataContext="{Binding Path=PrimaryContactDataContext.Value,Mode=TwoWay}" ContentTemplate="{StaticResource PersonalDetailsTemplate}" />
</StackPanel>
// See the Reusable template below
<UserControl.Resources>
<DataTemplate x:Key="PersonalDetailsTemplate" >
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Width="30" Text="Name"></TextBlock>
<TextBox Width="110" Text="{Binding LastName}" IsReadOnly="True"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Width="30" Text="Title"></TextBlock>
<TextBox Width="110" Text="{Binding firstName}" IsReadOnly="True"></TextBox>
</StackPanel>
</StackPanel>
</DataTemplate>
</UserControl.Resources>

Set the Content of the ContentControl, not its DataContext:
<ContentControl Content="{Binding Path=PrimaryContactDataContext.Value,Mode=TwoWay}" ContentTemplate="{StaticResource PersonalDetailsTemplate}" />

Related

Getting selected item from Treeview

I have a TreeView and want to get the selected item from it.
The Treeview itself is populated not manually, but from data in the code. Since it is populated this way, I'm not sure how to get information out of it.
Here is the XAML:
<TreeView Name="trvFamilies" HorizontalAlignment="Left" Margin="10,10,3,3" Width="340">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type self:Scene}" ItemsSource="{Binding Characters}">
<StackPanel Orientation="Horizontal">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="New" Click="MenuItem_Click"></MenuItem>
<MenuItem Header="Remove" Click="MenuItem_Click_1"></MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
<Image Source="{StaticResource ImageSceneRegular}" Margin="0,0,5,0" Width="64" Height="64"/>
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" [" Foreground="Blue" />
<TextBlock Text="{Binding Characters.Count}" Foreground="Blue" />
<TextBlock Text="]" Foreground="Blue" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type self:Character}">
<Border BorderThickness="1" Background="AliceBlue" CornerRadius="8,8,3,3">
<StackPanel Orientation="Horizontal" Margin="4" Background="White">
<Image Source="{Binding Img}" Margin="0,0,5,0" Width="64" Height="64" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" (" Foreground="Green" />
<TextBlock Text="{Binding Age}" Foreground="Green" />
<TextBlock Text=" years)" Foreground="Green" />
</StackPanel>
</Border>
</DataTemplate>
</TreeView.Resources>
</TreeView>
It is populated by data from an ObservableCollection which is populated within the code and then assigned to the ItemSource of the treeview (and it works fine).
So let's say I had a TextBlock which sat outside the TreeView and wanted to populate it with information from the selected Character (that's the type which populates the drop down part of the TreeView), I don't know how to do that, be it using XAML only or code behind.
Any help on how to do this would be very much appreciated.

How to Binding ListBox selected item and TextBox?

I have listBox and i want to see the selected item ftom the listBox on some textBox.
(the Collection is a list of string)
I trying to write the code but this is not working.
<ListBox x:Name="Collection__" Grid.Row="0" ItemsSource="{Binding Collection}" />
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Vertical" Margin="5">
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="Collection name:"/>
<TextBox DockPanel.Dock="Left" Margin="5,0" Text="{Binding ElementName=Collection__, Path=SelectedItem}"/>
</DockPanel>
</StackPanel>
found it ...
<StackPanel>
<ListBox x:Name="ElementListBox" ItemsSource="{Binding Elements}"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Text="{Binding Elements/Name}"/>
</StackPanel>

How to add a button outside datatemplate in itemscontrol

I have created a WPF app.In that I have a Datatemplate as follows
<DataTemplate x:Key="ItemTemplate">
<StackPanel>
<TextBlock Text="item"/>
<TextBlock Text="{Binding Number}"/>
</StackPanel>
</DataTemplate>
I have an ItemsControl like this
<ItemsControl ItemsSource="{Binding Items}"
Grid.Column="1"
Grid.Row="3"
ItemTemplate="{StaticResource ItemTemplateWithButton}" />
where I need a itemtemplate like this
<DataTemplate x:Key="ItemTemplateWithButton">
<StackPanel>
<StackPanel>
<TextBlock Text="item"/>
<TextBlock Text="{Binding Number}"/>
</StackPanel>
<StackPanel>
<Button>
<StackPanel>
<TextBlock Text="item"/>
<TextBlock Text="{Binding Number}"/>
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</DataTemplate>
Is there any possibility of reusing the datatemplate in the new itemscontrol?
You can use ContentControl too
<DataTemplate x:Key="ItemTemplate">
<StackPanel>
<TextBlock Text="item"/>
<TextBlock Text="{Binding Number}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ItemTemplateWithButton">
<StackPanel>
<ContentControl ContentTemplate="{StaticResource ItemTemplate}" />
<Button>
<ContentControl ContentTemplate="{StaticResource ItemTemplate}" />
</Button>
</StackPanel>
</DataTemplate>
What I understand by reading this answer and what Liero mentioned in the comments is it's possible to reuse a DataTemplate by using either ContentPresenter or ContentControl. However:
ContentPresenter is more lightweight.
ContentPresenter is designed to be used inside control templates.
ContnetPresenter is designed to be used as-is while ContentControl is designed to be extended (inherited from).
As a result, here is a solution based on what you asked:
<DataTemplate x:Key="ItemTemplate">
<StackPanel>
<TextBlock Text="item"/>
<TextBlock Text="{Binding Number}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ItemTemplateWithButton">
<StackPanel>
<ContentPresenter ContentTemplate="{StaticResource ItemTemplate}"/>
<StackPanel>
<Button Content="{Binding}" ContentTemplate="{StaticResource ItemTemplate}" />
</StackPanel>
</StackPanel>
</DataTemplate>
You could create a UserControl to hold the xaml you want to reuse:
<UserControl x:Class="StackOverflow.SharedControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel>
<TextBlock Text="item">
</TextBlock>
<TextBlock Text="{Binding Number}"></TextBlock>
</StackPanel>
</Grid>
</UserControl>
Then use this UserControl in both templates.
<DataTemplate x:Key="ItemTemplate">
<controls:SharedControl/>
</DataTemplate>
<DataTemplate x:Key="ItemTemplateWithButton">
<StackPanel>
<controls:SharedControl/>
<StackPanel>
<Button>
<StackPanel>
<TextBlock Text="item">
</TextBlock>
<TextBlock Text="{Binding Number}"></TextBlock>
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</DataTemplate>

How can I specify multiple DataTemplate in windows.resources for use by a ContentControl

How can I specify multiple DataTemplate in windows.resources for use by a ContentControl?
My code:
<Window.Resources>
<DataTemplate x:Key="CustomerTemplate" DataType="{x:Type local:Customer}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Occupation}"/>
<TextBlock Text=")"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="PersonTemplate" DataType="{x:Type local:Person}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
Thank you so much!
Use DataTemplateSelector to return the Datatemplate you want to be applied..
<ContentControl ContentTemplateSelector="{StaticResource MyTemplateSelector}"/>
here MYtemplateselector is DataTemplateSelector, in Select() method of selector you can check for the property bound to contentcontrol and return the corresponding Datatemplate.
Thanks
Remove x:Key from DataTemplate and try this:
<ContentControl Name="CustomerContentControl">
<local:Customer />
</ContentControl>
<ContentControl Name="PersonContentControl">
<local:Person />
</ContentControl>
In this article, Josh Smith show, how to get access the elements that are in the DataTemplate:
How to use FindName with a ContentControl

Binding to DataTemplate

I have a button template:
<DataTemplate x:Key="TemplateTest">
<Button Margin="10" BorderThickness="2" Content="{Binding Text}" />
</DataTemplate>
I want to create a textbox and a button whose content is the same as the textbox's text.
<TextBox x:Name="TextBox" Margin="10">TextBox</TextBox>
<ContentControl DataContext="{Binding ElementName=TextBox}"
ContentTemplate="{StaticResource ResourceKey=TemplateTest}" />
But I don't get anything on the button in this way.
#DanPuzey's one still did not work for me in VS2012. Not sure why it did in Kaxaml
This did:
<TextBox x:Name="TextBox"
Margin="10"
Text="Hello World" />
<ContentControl Content="{Binding ElementName=TextBox,
Path=.}"
ContentTemplate="{StaticResource TemplateTest}" />
and
<DataTemplate x:Key="TemplateTest">
<Button Height="100"
Margin="10"
BorderThickness="2"
Content="{Binding Text}" />
</DataTemplate>
This is failing, quite simply, because you aren't setting the content of your content control: setting the DataContext doesn't change anything. Try this:
<ContentControl Content="{Binding ElementName=TextBox}" ContentTemplate="{StaticResource ResourceKey=TemplateTest}" />
The above worked for me in Kaxaml, but if it's not working for you then I'd suggest you try this instead, which explicitly binds to the text of the textbox:
<ContentControl Content="{Binding Text, ElementName=TextBox}" ContentTemplate="{StaticResource ResourceKey=TemplateTest}" />
first you should set the content of your contentControl to be binded to the text
<TextBox x:Name="TextBox" Margin="10">TextBox</TextBox>
<ContentControl Content="{Binding ElementName=TextBox,Path=Text}"
ContentTemplate="{StaticResource ResourceKey=TemplateTest}" />
now you need change the binding of the button:
<DataTemplate x:Key="TemplateTest">
<Button Margin="10" BorderThickness="2" Content="{Binding}" />
</DataTemplate>
I am not sure if {Binding ElementName=TextBox} sets the default Binding.Path.
You might try setting the Path to . : DataContext="{Binding ElementName=TextBox, Path=.}"
Or you can bind directly the Text property of your element:
<TextBox x:Name="TextBox" Margin="10">TextBox</TextBox>
<ContentControl DataContext="{Binding Text, ElementName=TextBox}"
ContentTemplate="{StaticResource ResourceKey=TemplateTest}" />
and
<DataTemplate x:Key="TemplateTest">
<Button Margin="10" BorderThickness="2" Content="{Binding}" />
</DataTemplate>

Resources