grids Visibility binded to a TabControl SelectedItem - c#

I have two grids contained in borders like this :
<Border BorderBrush="Gray" BorderThickness="2" Margin="5" Visibility="{Binding SelectedItem, ElementName=tcAction, Converter={StaticResource LoadChangeHeaderToVisibilityConverter}}">
<Grid x:Name="actionGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text=" Card Name" HorizontalAlignment="Center" Margin="0,4,0,0" FontSize="16"/>
<Label Grid.Row="1" Content="{Binding CardName}" FontSize="14" HorizontalAlignment="Center" />
<TextBlock Grid.Row="2" Text="{Binding ActionType, StringFormat='Action Type: {0}'}" Margin="4" FontSize="13" FontWeight="ExtraBlack" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="3" Text="{Binding Action, StringFormat='Action: {0}'}" Margin="4" FontSize="13" FontWeight="ExtraBlack" HorizontalAlignment="Center"/>
</Grid>
</Border>
<Border BorderBrush="Gray" BorderThickness="2" Margin="5" Visibility="{Binding SelectedItem, ElementName=tcAction, Converter={StaticResource LoadChangeHeaderToVisibilityConverter}}">
<Grid x:Name="actionCANGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text=" CAN Name" HorizontalAlignment="Center" Margin="0,4,0,0" FontSize="16"/>
<Label Grid.Row="1" Content="{Binding CardName}" FontSize="14" HorizontalAlignment="Center" />
<TextBlock Grid.Row="2" Text="{Binding ActionType, StringFormat='Action Type: {0}'}" Margin="4" FontSize="13" FontWeight="ExtraBlack" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="3" Text="{Binding Action, StringFormat='Action: {0}'}" Margin="4" FontSize="13" FontWeight="ExtraBlack" HorizontalAlignment="Center"/>
</Grid>
</Border>
Both of them are binded to the SelectedItem property of a TabControl. The fact here is that i want only one grid visible at a time, depending on the TabItem selected. So when Visibility is Visible for one of them, it should be Hidden for others. I am not sure how can i track the states of all the future grids, and keep only 1 in the front.

Personally I wouldn't mess with Visibility at all. That's the old WinForms way :)
Instead, I'd use a ContentControl and switch the ContentTemplate property in a DataTrigger based on the SelectedItem. I find this easier to maintain, and there's only one set of items in the visual tree at a time.
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyTabControl, Path=SelectedIndex}" Value="0">
<Setter Property="ContentTemplate" Value="{StaticResource ActionTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=MyTabControl, Path=SelectedIndex}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource ActionCANTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>

Instead of binding the SelectedItem of the tabcontrol, Bind SelectedIndex and pass the convertParamereter to the Converter
Your Converter will be like below
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((int)value == (int)parameter)
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
And in your Xmal change the visibility as below
Visibility="{Binding SelectedIndex, ElementName=tcAction, Converter={StaticResource LoadChangeHeaderToVisibilityConverter}, ConverterParameter=0}">

Related

How to use an if expression in Binding WPF - c#

Here is my code:
<ListView Grid.Row="1" x:Name="viewTicket" Style="{StaticResource ticketListBox}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="Transparent" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" BorderBrush="{x:Null}" SelectionChanged="ViewTicket_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Image Visibility="{Binding selectedCheck}" Name="check" Grid.Column="0" Margin="10,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" Source="../../Images/check-donatota.png" Stretch="None" MouseLeftButtonUp="Check_MouseLeftButtonUp"/>
<TextBlock Visibility="{Binding selectedQuantity}" Name="quantity" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding amount}"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Black" TextWrapping="Wrap" Text="{Binding name}"/>
<TextBlock Visibility="{Binding selectedPrice}" Name="price" Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding total, StringFormat=C}"/>
<Image Visibility="{Binding selectedTrash}" Name="trash" Grid.Column="2" Margin="0,0,15,0" HorizontalAlignment="Right" VerticalAlignment="Center" Source="../../Images/trash-donatota.png" Stretch="None" MouseLeftButtonUp="Trash_MouseLeftButtonUp"/>
</Grid>
<ListView
ItemsSource="{Binding ingredients}"
Grid.Row="1"
Margin="-5,0,0,0"
Name="viewTicketIngs"
IsHitTestVisible="False"
Style="{StaticResource ticketListBox}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
Background="Transparent"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Center"
BorderBrush="{x:Null}"
SelectionChanged="ViewTicketIngs_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Visibility="Visible" Name="quantity" Grid.Column="0" Foreground="{DynamicResource GrayTextDonaTotaBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding amount}"/>
<TextBlock Margin="10,0,0,0" Grid.Column="1" Foreground="{DynamicResource GrayTextDonaTotaBrush}" HorizontalAlignment="Left" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding ing.name}"/>
<TextBlock Visibility="Visible" Name="price" Grid.Column="2" Foreground="{DynamicResource GrayTextDonaTotaBrush}" HorizontalAlignment="Right" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding total, StringFormat=C}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I add data to the ListView viewTicket, but depending of a property I would like to change the ItemSource Binding of the ListView viewTicketIngs. In other words, is there anyway that I can use an if expression on the binding? Something like ItemsSource="{Binding IF(mode == 0) {ingredients} else {plates}}"
Change the Binding by a DataTrigger in a Style:
<ListView ...>
<ListView.Style>
<Style TargetType="ListView">
<Setter Property="ItemsSource" Value="{Binding plates}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding mode}" Value="0">
<Setter Property="ItemsSource" Value="{Binding ingredients}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
As I understand it, you sometimes dispaly plates, sometimes ingredients. Now there are triggers conditional display. WPF actually has a pretty wide support.
However what might be better is to have 2 different ViewModel classes and two (how I call them) "type targetting data tempaltes". Say you have these clases:
abstract class ViewModelItem { }
class Plate : ViewModelItem { }
class IngredientsList : ViewModelItem { }
The propety you exposie this in, would be set to ViewModelItem. In realtiy you would assign either a Plate or IngredientsList Instance.
Now you define two DataTemplates. A interesting thing about WPF is that if you do not specify a explicit Template, the Code will go out of it's way to try to find one. And it will do the matching via the DataType property of the Template (TargetType for Styles and similar). It works similar to what CSS does, with somebodies code going out of it's way to find a template to apply.

C# WPF - ListBox with DataTemplate - add extra "header" row

I have ListBox with DataTemplate, like this:
<ListBox ItemsSource="{Binding}" BorderBrush="Transparent"
Grid.IsSharedSizeScope="True"
HorizontalContentAlignment="Stretch"
Grid.Row="1"
Grid.Column="0" Grid.ColumnSpan="4"
Name="playerList">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="2">
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="16" />
<TextBlock Grid.Column="1" Text="{Binding Drinked }" FontWeight="Bold" FontSize="16" />
<TextBlock Grid.Column="2" Text="{Binding Remaining }" FontWeight="Bold" FontSize="16" />
<Button Grid.Column="3" Name="addButton" Click="addButton_Click" FontWeight="Bold" FontSize="16">+</Button>
<Button Grid.Column="4" Name="substractButton" Click="substractButton_Click" FontSize="16">-</Button>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have class that has the properties Name, Drinked, etc. It's in List<> that is set as DataSource. This part works fine.
But I need to add extra entry to this ListBox, that will be displayed before the DataTemplate. It will not have bindings or the same structure - it will serve as header and will have different layout than the DataTemplate.
Is there any way to do it? If I add it like in a normal ListBox, I then got an error that the ListBox must be empty before using binding.
Now the ListBox looks like this:
But I need to make it looks like this:
Is it possible to do so? If there is way to do it using other element than ListBox, I'm fine with it, as long as I can use Binding and DataTemplate.
If scrollign doesn't matter to you can put simply a static border just above your listbox..
For the scenario where you want to include that extra row in the scrolling you have to modify ListBox's template. Here is an example of an implicit style that would add a TextBlock just before your items and that would participate of the scrolling:
<Style TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<ScrollViewer x:Name="ScrollViewer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="I am an extra row" Grid.Row="0"/>
<ItemsPresenter Grid.Row="1"/>
</Grid>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In fact by overriding the control's template you can give it all the customizations that you need... You can change the textblock for whatever any other control you want..
You could achieve this goal by using a Stackpanel or Grid. However, if you insist on using an extra row in your ListBox, you can make use of a Content Template Selector. In the following solution, I did use a trigger to set the template of the current item according to its type.
<Window.Resources>
<local:ObjectToTypeConverter x:Key="ObjectToTypeConverter" />
<ControlTemplate x:Key="emptyRow">
<Grid HorizontalAlignment="Stretch">
<Border Height="50" BorderBrush="Black" BorderThickness="2">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Extra row that is not part of the binding or DataTemplate" />
</Border>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="default">
<Border BorderBrush="Black" BorderThickness="2">
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="16" />
<TextBlock Grid.Column="1" Text="{Binding Drinked }" FontWeight="Bold" FontSize="16" />
<TextBlock Grid.Column="2" Text="{Binding Remaining }" FontWeight="Bold" FontSize="16" />
<Button Grid.Column="3" Name="addButton" Click="addButton_Click" FontWeight="Bold" FontSize="16">+</Button>
<Button Grid.Column="4" Name="substractButton" Click="substractButton_Click" FontSize="16">-</Button>
</Grid>
</Border>
</ControlTemplate>
<Style x:Key="ItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template" Value="{DynamicResource emptyRow}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ., Converter={StaticResource ObjectToTypeConverter}}" Value="{x:Type local:Model}">
<Setter Property="Template" Value="{DynamicResource default}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding}" BorderBrush="Transparent"
Grid.IsSharedSizeScope="True"
HorizontalContentAlignment="Stretch"
Grid.Row="1"
ItemContainerStyle="{StaticResource ItemStyle}"
Grid.Column="0" Grid.ColumnSpan="4"
Name="playerList" />
</Grid>
The converter simply converts the object to its type
public class ObjectToTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value?.GetType();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
To add different objects to your collection, change the type to object or to a type according to your inheritance setup.

Link a ListBox Borderbrush property to a IsEnabled button

I have two TextBoxes, two ListBoxes, a Cancel button and an OK button.
Simplifying the problem, I would like to link the color of the Borderbrush of the second ListBox to the IsEnabled property of the OK button.
An alternative would be link that color change to the ListBoxItem background instead of the Listbox border itself.
Is it possible (maybe through Triggers or something)? If so, could you show me the way?
The XAML of the window is as follows:
<Window x:Class="Opt.ExpertSystem.View.WindowPasteRules"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:scroll="clr-namespace:Opt.ExpertSystem.View"
Title="Paste Rules Options" Width="400" Height="300">
<Window.InputBindings>
<KeyBinding Key="Esc" Command="{Binding CancelCommand}" />
</Window.InputBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="100*"/>
<RowDefinition Height="35"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="76*" />
</Grid.ColumnDefinitions>
<Label Content="Select Rules to Paste: " Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" HorizontalContentAlignment="Right" Margin="0,0,2,0" Width="Auto"/>
<Grid Grid.Row="1" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid.Resources>
<Style TargetType="ScrollViewer">
<Setter Property="scroll:ScrollSynchronizer.ScrollGroup" Value="Group1" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="50*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Content="Replace" HorizontalAlignment="Stretch" FontWeight="Bold"/>
<TextBox Margin="55,2,2,2" Text="{Binding CopyNameOrigin}" ToolTip="Non-editable field. Represents the text you want to replace." Focusable="False"/>
<Label Content="With" Grid.Column="2" HorizontalAlignment="Stretch" FontWeight="Bold"/>
<TextBox Grid.Column="2" Margin="42,2,2,2" Text="{Binding CopyNameNew, UpdateSourceTrigger=PropertyChanged}" ToolTip="Represents the results of the changes to be made." />
<ListBox ItemsSource="{Binding Path=CopiedRules}" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" BorderThickness="1" BorderBrush="CornflowerBlue" Grid.IsSharedSizeScope="True" Margin="2,0,2,10" >
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox ItemsSource="{Binding Path=PasteRules}" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="2" BorderThickness="1" BorderBrush="CornflowerBlue" Margin="2,0,2,10" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="2,5,2,5" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<Grid Grid.Row="2" Background="#FFECE9D8" Grid.ColumnSpan="2">
<Button Content="OK" x:Name="btnOK" IsEnabled="{Binding IsValid, UpdateSourceTrigger=PropertyChanged}" Margin="0,6,6,0" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75" Height="23" Click="btnOK_Click" />
<Button Content="Cancel" x:Name="btnCancel" IsCancel="True" Margin="0,6,90,0" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75" Height="23" />
</Grid>
</Grid>
</Window>
Here's a small example that changes the border brush of a listview based on the IsEnabled property of a button
<StackPanel>
<ListBox Height="100">
<ListBox.Style>
<Style TargetType="ListBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=okButton, Path=IsEnabled}" Value="false">
<Setter Property="BorderBrush" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=okButton, Path=IsEnabled}" Value="true">
<Setter Property="BorderBrush" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
<Button IsEnabled="True" Name="okButton">true</Button>
</StackPanel>
But I would set the availability of the button on the command and not in the XAML, also I would bind the color of the ListView to the IsValid property in the ViewModel instead.

XAML Conditional Binding in DataTemplate

I have a DataTemplate for a ListView in XAML:
<DataTemplate x:Key="ResultItemTemplate">
<Grid Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name}"
Margin="0,10,20,0"
Grid.Column="0"
Grid.Row="0"/>
<TextBlock Text="{Binding TimeStamp}"
Margin="0,10,10,0"
Grid.Column="1"
Grid.Row="0"/>
<TextBlock Text="{Binding Text}"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="1"
TextWrapping="Wrap"
Height="auto"
Margin="0,0,10,10"/>
<TextBlock Text="{Binding Additional}"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
TextWrapping="Wrap"
Height="auto"
Margin="0,0,10,20" />
</Grid>
</DataTemplate>
So applying this DataTemplate to my ListView, the Additional TextBlock is not present in every list item.
However the spacing exists for the Additional TextBlock whether the DataBinding value is null or not.
How do I get the text block to only be added when the 'Additional' Binding property exists?
This is your Converter:
namespace ValueConveters
{
public class NullToVisibilityConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value == null ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
}
And this is your XAML:
put this in your root element:
xmlns:conveters="clr-namespace:ValueConveters"
and then this in your Resources:
<conveters:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
<DataTemplate x:Key="ResultItemTemplate">
<Grid Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name}"
Margin="0,10,20,0"
Grid.Column="0"
Grid.Row="0"/>
<TextBlock Text="{Binding TimeStamp}"
Margin="0,10,10,0"
Grid.Column="1"
Grid.Row="0"/>
<TextBlock Text="{Binding Text}"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="1"
TextWrapping="Wrap"
Height="auto"
Margin="0,0,10,10"/>
<TextBlock Text="{Binding Additional}"
Visibility="{Binding Additional,Converter={StaticResource NullToVisibilityConverter}}"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
TextWrapping="Wrap"
Height="auto"
Margin="0,0,10,20" />
</Grid>
</DataTemplate>
Based on Flat Eric's suggestion - fields can be bound to the IsVisible property:
<Label IsVisible="{Binding Foo}" Text="{Binding Foo}"/>
When the value is null the Label is hidden.
To collapse the TextBlock when Additional property is not available, try to bind TextBlock's Visiblity property with TargetNullValue set to Collapsed. I would suggest something like this :
<TextBlock Text="{Binding Additional}"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
TextWrapping="Wrap"
Height="auto"
Margin="0,0,10,20"
Visibility="{Binding Additional, TargetNullValue=Collapsed}"
/>
But turned out it doesn't work for me, for a reason I don't know. But binding this way did the trick :
<TextBlock DataContext="{Binding Additional}"
Text="{Binding}"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
TextWrapping="Wrap"
Height="auto"
Margin="0,0,10,20"
Visibility="{Binding TargetNullValue=Collapsed}"
/>
Related questions :
How to Set TargetNullValue to Visibility.Collapsed in Binding
Control not being hidden when binding source is null
Binding Visibility to DataContext
You can try use the BindingBase.TargetNullValue for this:
<TextBlock Margin="{Binding Path=MyMargin, TargetNullValue=0}" />
Beforehand to create a property MyMargin of Thickness? type with some default value. If value of MyMargin will be null value, then value take from TargetNullValue.
You can edit the style of the textblock and set the visibility to collapsed or visible based on the value of the binding. The latter can be done using datatriggers.
It will be easier if you create a property ShowAdditional, which returns true or false, based on the value of the binding. This way you can easily customize when to show it or not.
As follows:
<TextBlock Text="{Binding Additional}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" TextWrapping="Wrap" Height="auto" Margin="0,0,10,20">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowAddition}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding CameraState}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
With visiblity set to collapsed, the entire element will be collapsed, including its margin.

XAML - Bind combobox in DataTemplate to a collection?

Firstly, thank you for taking the time out to read this post. All contributions are very much appreciated.
I'm having difficulty understanding how I can bind a ComboBox ItemsSource within a DataTemplate to an ObservableCollection.
Here's my code thus far:
DataTemplate Template (notice the combo's at the bottom of the template):
<DataTemplate x:Key="ListBoxCustomTemplate">
<Grid Margin="4" HorizontalAlignment="Stretch" x:Name="lstBoxItemRoomGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" FontWeight="Bold" Text="{Binding TemplateGroupName}" />
<Image x:Name="imgDeleteListBoxItem" Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" Source="/Icons/Print-Groups-Config/delete-32.png" Height="25" Cursor="Hand"
ToolTip="Remove template" VerticalAlignment="Center"
HorizontalAlignment="Right" MouseLeftButtonUp="imgDeleteListBoxItem_MouseLeftButtonUp">
<Image.Style>
<Style>
<Setter Property="Image.Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=lstBoxItemRoomGrid}" Value="True">
<Setter Property="Image.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding TemplateDescription}" TextWrapping="WrapWithOverflow" />
<!-- Header Template Selection -->
<Label Grid.Row="2" Grid.Column="0" Margin="0,3,0,0" HorizontalAlignment="Left" VerticalAlignment="Bottom" Content="Select Header:" FontWeight="DemiBold" Foreground="DarkGray" />
<telerik:RadComboBox x:Name="radComboHeaderTemplate" Grid.Row="3" Grid.Column="0" Width="120" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center"
ClearSelectionButtonVisibility="Visible" SelectedValue="{Binding TemplateHeaderID}" />
<!-- Footer Template Selection -->
<Label Grid.Row="2" Grid.Column="1" Margin="0,3,0,0" HorizontalAlignment="Left" VerticalAlignment="Bottom" Content="Select Footer:" FontWeight="DemiBold" Foreground="DarkGray" />
<telerik:RadComboBox x:Name="radComboFooterTemplate" Grid.Row="3" Grid.Column="1" Width="120" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center"
ClearSelectionButtonVisibility="Visible" SelectedValue="{Binding TemplateFooterID}" />
</Grid>
</DataTemplate>
When my Window loads, I download the collection data from my database and store into a local collection. Note that there are two Collections, one for each of the 2 ComboBoxes in my DataTemplate.
//Header Templates
private ObservableCollection<TemplateHeaderFooter> templatesHeader = new ObservableCollection<TemplateHeaderFooter>();
//Footer Templates
private ObservableCollection<TemplateHeaderFooter> templatesFooters = new ObservableCollection<TemplateHeaderFooter>();
//--- Constructors ---
public PrintTemplateGroupsConfigWindow()
{
InitializeComponent();
//Download Data From DB
this.templatesHeader = TemplateHeaderFootersDB.GetAllTemplatesOfType(1);
this.templatesFooters = TemplateHeaderFootersDB.GetAllTemplatesOfType(2);
}
How do I get the collection Data templatesFooters & templatesHeader into the the ItemsSources of their respective ComboBoxes?
The datatemplate is for a ListBox.
<telerik:RadListBox x:Name="lstBoxPrintGroupTemplates" Height="300" Width="280" ItemsSource="{Binding}" IsEnabled="False"
ItemTemplate="{StaticResource ListBoxCustomTemplate}" Style="{StaticResource DraggableListBox}" >
Many thanks. Any help is appreciated.
Define properties wrappers over the variables of your collections and then you can bind them to comboboxes as:
ItemsSource="{Binding TemplatesHeader, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
public ObservableCollection<TemplateHeaderFooter> TemplatesHeader
{
get{return templatesHeader;}
}
Similarly you can do for other property

Categories

Resources