Reference converter in another xaml - wpf

I got a datatemplate in Resource.xaml:
<DataTemplate x:Key="SplitViewMenuItemWithCount">
<RelativePanel>
<RelativePanel RelativePanel.AlignVerticalCenterWithPanel="True" Margin="0,10,0,10">
<SymbolIcon Foreground="White" Width="25" RelativePanel.AlignVerticalCenterWithPanel="True" Symbol="{Binding Symbol}" x:Name="SymbolIcon" Margin="10,0,0,0"/>
<StackPanel Visibility="{Binding Count, Converter={StaticResource BooleanToVisibilityConverter}, TargetNullValue=Collapsed, FallbackValue=Collapsed}" x:Name="StackPanelCount" RelativePanel.RightOf="SymbolIcon" Margin="0,20,0,0" CornerRadius="9" Background="White" Width="15" Height="15">
<TextBlock Text="{Binding Count, FallbackValue='0'}" TextAlignment="Center" FontSize="10" Foreground="{StaticResource AppDarkBlueColor}"/>
</StackPanel>
<TextBlock Margin="10,0,0,0" Foreground="White" x:Name="TextBlockMenuItemText" RelativePanel.RightOf="StackPanelCount" Text="{Binding Text}" FontSize="16" Padding="5,3,0,5"/>
</RelativePanel>
</RelativePanel>
</DataTemplate>
I'm using the datatemplate in my MainPage.xaml as a datatemplate for a ListView, but it crashes because my BooleanToVisibilityConverter. It can't find the converter in Resource.xaml.
However if I put the datatemplate in my MainPage.Resources it finds the converter (because it's defined there).
Is there any way to keep the datatemplate in Resource.xaml? I rather have it there than in MainPage.Resources.

You have to add a reference from your mainPage.xaml to your resources.xaml by using ResourceDictionnary tag as following:
<Window x:Class="MainPage" ... ... >
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/YourProjectDLL;component/Resource.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
... Your window body
</Grid>
</Window>

Related

WPF ContentControl DataTemplate not updating value

I have no idea what's happening here. When I bind directly to a TextBox the value can be edited, but I want to bind in a ContentControl.
Why doesn't the ContentControl update the ViewModel?
<Window x:Class="WTFWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WTFWPF"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow"
Width="525"
Height="350"
DataContext="{DynamicResource ViewModel}"
mc:Ignorable="d">
<Window.Resources>
<local:MainViewModel x:Key="ViewModel" />
<DataTemplate DataType="{x:Type sys:Int32}">
<TextBox Text="{Binding Path=., UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</Window.Resources>
<StackPanel>
<TextBlock Margin="5" Text="{Binding Number}" />
<TextBox Margin="5" Text="{Binding Number, UpdateSourceTrigger=PropertyChanged}" />
<ContentControl Margin="5" Content="{Binding Number}" />
</StackPanel>
</Window>
This seem to work fine, not sure why your version doesn't work though.
<Window.Resources>
<wpfApplication1:MainViewModel x:Key="ViewModel" />
<DataTemplate x:Key="NumberTemplate">
<TextBox Text="{Binding Path=Number, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</Window.Resources>
<StackPanel>
<TextBlock Margin="5" Text="{Binding Number}" />
<TextBox Margin="5" Text="{Binding Number, UpdateSourceTrigger=PropertyChanged}" />
<ContentControl Margin="5"
Content="{Binding}"
ContentTemplate="{StaticResource NumberTemplate}" />
</StackPanel>
Another way of making it work is to change the binding in the template:
<TextBox Text="{Binding Path=DataContext.Number,
RelativeSource={RelativeSource AncestorType=ContentControl}, UpdateSourceTrigger=PropertyChanged}" />
Unfortunately I can't explain why your version doesn't work.

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 to get ContentControl to resolve DataTemplate

Why does this not resolve the datatemplate?
<Window.Resources>
<DataTemplate DataType="system:DateTime" >
<Grid Background="Aqua">
<TextBlock Text="{Binding Day}"></TextBlock>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl Content="{x:Static system:DateTime.Now}"/>
</Grid>
Writing a TemplateSelector feels like an overkill.
DataType design suggests the presence of a directive x:Type like that:
<DataTemplate DataType="{x:Type system:DateTime}">
<Grid Background="Aqua">
<TextBlock Text="{Binding Day}" Height="30" Width="100" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
See the MSDN for more information.

Reusing a tooltip for several textboxes

What should I write in the value of the Text property of the tooltip resource so it would show the text of each textblock dynamically ?
<StackPanel x:Name="root">
<StackPanel.Resources>
<ResourceDictionary>
<ToolTip x:Key="tooltiptemplate">
<TextBlock Background="LightBlue" TextTrimming="WordEllipsis" Text="?????"/>
</ToolTip>
</ResourceDictionary>
</StackPanel.Resources>
<TextBlock Text="Mickel" ToolTip="{StaticResource tooltiptemplate}"/>
<TextBlock Text="Kim" ToolTip="{StaticResource tooltiptemplate}"/>
<TextBlock Text="Jenny" ToolTip="{StaticResource tooltiptemplate}"/>
</StackPanel>
{Binding PlacementTarget.Text, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}

Are recursive DataTemplates possible?

I have a class something like:
public class Section
{
private IEnumerable<Section> sections;
private IEnumerable<KeyValuePair<string, string>> attributes
public string Name {get;set;}
public IEnumerable<Section> Sections
{
get {return sections;}
}
public IEnumerable<KeyValuePair<string, string>> Attributes
{
get {return attributes;}
}
public Section(...)
{
//constructor logic
}
}
Which is contained in another class, lets call it OtherClass for sake of argument, that wraps around it and is used in WPF in an ObjectDataProvider.
As you can see, an instance of Section can contain many other instances of Section.
Is there a way in XAML to create a template that deals with this recursion?
This is what I've got so far:
<UserControl x:Class="OtherClassEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:OtherClassNS="clr-namespace:NameSpace"
Height="300" Width="300">
<UserControl.Resources>
<ObjectDataProvider ObjectType="{x:Type OtherClassNS:OtherClass}" x:Key="ViewModel" />
<DataTemplate x:Key="listViewAttr">
<WrapPanel>
<TextBlock Text="{Binding Path=Key}"></TextBlock><TextBlock Margin="0,0,4,0">: </TextBlock>
<TextBlock Text="{Binding Path=Value}"></TextBlock>
</WrapPanel>
</DataTemplate>
<DataTemplate x:Key="listViewSection">
<StackPanel>
<WrapPanel Margin="0,0,0,8">
<TextBlock Margin="0,0,4,0">Section:</TextBlock>
<TextBlock Text="{Binding Path=Name}"/>
</WrapPanel>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="listViewData">
<StackPanel>
<WrapPanel Margin="0,0,0,8">
<TextBlock Margin="0,0,4,0">Section: </TextBlock>
<TextBlock Text="{Binding Path=Name}"/>
<ListView DataContext="{Binding Path=Sections}" ItemTemplate="{StaticResource listViewSection}" ItemsSource="{Binding Sections}">
</ListView>
<ListView DataContext="{Binding Path=Attributes}" ItemsSource="{Binding Attributes}" ItemTemplate="{StaticResource listViewAttr}">
</ListView>
</WrapPanel>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListView DataContext="{StaticResource ViewModel}" ItemTemplate="{StaticResource listViewData}" ItemsSource="{Binding Sections}">
</ListView>
</Grid>
</UserControl>
But I can't get recursion, as a DataTemplate can only reference one that is declared before it.
Can this be done in XAML? If so, how? Is this something that I'll have to do in code behind?
Are DataTemplates even the way to go? Is there a better way to display and edit this data?
In case anyone needs to see how to do this without using an HierarchicalDataTemplate:
<UserControl x:Class="OtherClassEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:OtherClassNS="clr-namespace:NameSpace"
Height="300" Width="300">
<UserControl.Resources>
<ObjectDataProvider ObjectType="{x:Type OtherClassNS:OtherClass}" x:Key="ViewModel" />
<DataTemplate x:Key="listViewAttr">
<WrapPanel>
<TextBlock Text="{Binding Path=Key}"></TextBlock>
<TextBlock Margin="0,0,4,0">: </TextBlock>
<TextBlock Text="{Binding Path=Value}"></TextBlock>
</WrapPanel>
</DataTemplate>
<DataTemplate x:Key="listViewData">
<StackPanel>
<WrapPanel Margin="0,0,0,8">
<TextBlock Margin="0,0,4,0">Section: </TextBlock>
<TextBlock Text="{Binding Path=Name}"/>
</WrapPanel>
<ListView ItemTemplate="{DynamicResource listViewData}" ItemsSource="{Binding Sections}" />
<ListView ItemsSource="{Binding Attributes}" ItemTemplate="{StaticResource listViewAttr}" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListView DataContext="{StaticResource ViewModel}" ItemTemplate="{DynamicResource listViewData}" ItemsSource="{Binding Sections}">
</ListView>
</Grid>
</UserControl>
This gets me basically what I want.
The main change is as Dan Bryant suggested: changing the ItemTemplate to use a Dynamic rather than static resource for the recursive object (Section).
Perhaps I'm misunderstanding your scenario, but is HierarchicalDataTemplate what you're looking for?

Resources