How to disable DataTemplate at a specific place? - wpf

Consider the following model:
var model = new object[] { "Ala ma kota", DateTime.Now };
Now, let's suppose, that we have the following DataTemplates for ListBox displaying this model:
<ListBox ItemsSource="{Binding Data}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type sys:String}">
<StackPanel Orientation="Horizontal">
<TextBlock>String:</TextBlock>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType={x:Type sys:DateTime}">
<StackPanel Orientation="Horizontal">
<TextBlock>Data i czas:</TextBlock>
<Calendar DisplayDate={Binding Mode=OneWay}" />
</StackPanel>
</DataTemplate>
</ListBox.Resources>
</ListBox>
If we run such program, quite funny effect will be achieved:
Is there a way to disable DataTemplate on some level? I'd like to "block" it in the second DataTemplate, such that the calendar will be displayed correctly.

One way i can think of is to take advantage of resource lookup behaviour in WPF. It traverses up the Visual tree till found a default resource for a control.
You can define resource locally for string inside dataTemplate of DateTime so that it gets applied locally for your DateTime template and for others it will continue to behave same:
<DataTemplate DataType="{x:Type sys:DateTime}">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<DataTemplate DataType="{x:Type sys:String}">
<TextBlock Text="{Binding}"/>
</DataTemplate>
</StackPanel.Resources>
<TextBlock>Data i czas:</TextBlock>
<Calendar DisplayDate="{Binding Mode=OneWay}" />
</StackPanel>
</DataTemplate>
Output:

Related

WPF DataTemplate and binding with TextBlock

<Window.Resources>
<DataTemplate x:Key="pointGroupTemplate" DataType="{x:Type ac:PointGroup}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
<DataTemplate x:Key="tt2" DataType="{x:Type ac:PointGroup}">
<TextBlock Text="{Binding PointsCount}"/>
</DataTemplate>
</Window.Resources>
the first template works well with:
<ComboBox x:Name="comboBox1" ItemTemplate="{StaticResource pointGroupTemplate}" SelectionChanged="ComboBox1_SelectionChanged"
Height="25" Margin="0,5,0,5">
but i want to use the second one in a textblock
<TextBlock x:Name="textBlock1" Text="{Binding ElementName=comboBox1 ,Path=SelectedItem ?????}"/>
anyhelp.
In order to have a DataTemplate applied, you need a ContentPresenter or ContentControl:
<ContentControl ContentTemplate="{StaticResource tt2}"
Content="{Binding SelectedItem, ElementName=comboBox1}"/>

TreeView with multiple levels

Of the following code
<TreeView Name="tree" ItemsSource="{Binding Path=AllNotes}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type m:Note}" ItemsSource="{Binding Path=ListIssuesType}">
<TextBlock Text="{Binding Path=SoftwareVersion}" Margin="2" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type m:IssueType}" ItemsSource="{Binding Path=IssueNames}">
<TextBlock Text="{Binding Path=IssueTypeName}" Margin="2" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type m:IssueType}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=IssueTypeName}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
I get the error:
"Item has already been added. Key in dictionary: 'DataTemplateKey(ReleaseNotes_Window.Models.IssueType)' Key being added: 'DataTemplateKey(ReleaseNotes_Window.Models.IssueType)'"
When you put something into a ResourceDictionary it either needs an explicit x:Key or the key will be determined by the DictionaryKeyPropertyAttribute applied on the class.
For DataTemplate it is the following:
[DictionaryKeyProperty("DataTemplateKey")]
public class DataTemplate : FrameworkTemplate
This will depend on the DataType.
Because you have:
<HierarchicalDataTemplate DataType="{x:Type m:IssueType}" ItemsSource="{Binding Path=IssueNames}">
<TextBlock Text="{Binding Path=IssueTypeName}" Margin="2" />
</HierarchicalDataTemplate>
And
<DataTemplate DataType="{x:Type m:IssueType}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=IssueTypeName}" />
</StackPanel>
</DataTemplate>
Both with DataType="{x:Type m:IssueType}", that's why the program fails.
Use an additional x:Key for one of the DataTemplates and reference it as a StaticResource where you're planning to use it.

WPF binding Listbox layoutpanel

I´m using devexpress and I want to do a binding with a Listbox, but I have an error. Here my code:
<ListBox x:Name="_list" >
<ListBox.ItemTemplate>
<DataTemplate>
<dxd:LayoutPanel
Caption="{Binding nameList}"
AllowHide ="False" AllowFloat="False"
GotFocus="panel_GotFocus" >
<TextBox Text="Hello" />
</dxd:LayoutPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With this code, Caption {Binding nameList} is empty.
I have tried this.
<ListBox x:Name="_list" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBox Text="{Binding nameList}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this case, text in TextBox is correct, I need to use the first code.
You seem to be a bit confused about how to use this ListBox. First, you need a collection property to bind to the ListBox.ItemsSource property. Let's say you have a collection of User objects called Users:
<ListBox ItemSource="{Binding Users}" />
Now we want to define how each User should be displayed... all the properties of the User class will be available to the Binding inside the DataTemplate. Let's say that the User class has two properties; Name and Age:
<DataTemplate DataType="{x:Type YourDataTypeNamespace:User}">
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Age}" />
</StackPanel>
</DataTemplate>
Then putting it all together:
<ListBox ItemSource="{Binding Users}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type YourDataTypeNamespace:User}">
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Age}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Data Binding with WPF

I'm new to WPF and this following has stumped me for a while now:
I have an observableCollection of People object in my model that is bound to my tabControl. So each my a new People object is added, a new tab is created with People.Title as the Tab's header.
Each People object has an ObservableCollection of Friend object. Inside of the Tab I would like to have a List of two textboxes, one for Friend.FirstName and another for Friend.LastName.
My first requirement is working fine, but the second one is giving me an error 'ItemsSource is already in use'
Here's my code so far:
<TabControl Name="ConversationTabs" Grid.Row="0"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource HeaderInfoTabControl}"
ContentTemplate="{StaticResource DialogueList}" />
<Window.Resources>
<DataTemplate x:Key="HeaderInfoTabControl">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
<DataTemplate x:Key="DialogueList">
<ItemsControl ItemsSource="{Binding Path=DialogueCollectionVM}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Sent}" />
<TextBlock Text="{Binding Path=DateSent}" />
<TextBlock Text="{Binding Path=Message}" />
</StackPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
I appreciate your help.
You cannot add items to an ItemsControl and use the automatic population (via ItemsSource) at the same time. If that StackPanel is supposed to be used for the items in the ItemsSource you should do this:
<ItemsControl ItemsSource="{Binding Path=DialogueCollectionVM}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Sent}" />
<TextBlock Text="{Binding Path=DateSent}" />
<TextBlock Text="{Binding Path=Message}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

How can I change Item and Content Templates based on the object type?

I have a WPF TabControl that I have set the ItemTemplate as well as the ContentTemplate. This tab control displays Call Log information based on customer tech support information.
Inside of this same control, I would also like to be able to show a ReturnAuthorization template.
I would like to swap these out based on the object type added to the TabControl's Items collection. Is this something that is possible?
I have some Pseudo-code that sort of shows what I want to pull off:
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True" ItemContainerStyle="{StaticResource ClosableTabItemTemplate}" >
<TabControl.ItemTemplate>
if ( Type is Entities:Case )
{
<DataTemplate DataType="{x:Type Entities:Case}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
}
else if ( Type is Entities1:RAMaster )
{
<DataTemplate DataType="{x:Type Entities1:RAMaster}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
}
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
One way to do this is using something like an ItemTemplateSelector, which you can set on the TabControl. However, if you only need the different templates within the TabControl and know what they all are ahead of time, then you can just let them automatically be applied by using the DataTypes.
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True" ItemContainerStyle="{StaticResource ClosableTabItemTemplate}" >
<TabControl.Resources>
<DataTemplate DataType="{x:Type Entities:Case}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
<DataTemplate DataType="{x:Type Entities1:RAMaster}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
</TabControl.Resources>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>

Resources