Changing ContentTemplate based on ListBox selection - wpf

I have a Listbox and a Border in a StackPanel similar to the following:
<StackPanel Orientation="Horizontal">
<ListBox>
<ListBoxItem Content="People"/>
<ListBoxItem Content="Animals"/>
<ListBoxItem Content="Cars"/>
</ListBox>
<Border Width="200>
<ContentPresenter/>
</Border>
</StackPanel>
When selecting an item in the listbox I would like to change the content in the ContentPresenter accordingly e.g. selecting People would change the template to display a series of input fields related to people where as selecting Animals would display a series of fields related to Animals etc. - the behavior of this would be akin to a TabControl.
I think I can achieve this with a DataTrigger which changes the DataTemplate in the Border but I'm not sure how to achieve this.
Any pointers?
Thanks

You can toggle the ContentTemplate using a DataTrigger as follows.
Note, that I am binding an ObservableCollection to a simple object (Thing) with one property called Name, and am I binding the Content of the ContentControl to the SelectedItem in the ListBox using a ViewModel.
<Grid>
<Grid.Resources>
<local:MultiValueConverter x:Key="con" />
<DataTemplate x:Key="PeopleTemplate">
<StackPanel Orientation="Horizontal">
<Label Margin="0,0,5,0" Content="People Name" HorizontalAlignment="Left" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100" Height="25"></TextBox>
<Button Content="OK" Grid.Column="2" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="AnimalsTemplate">
<StackPanel Orientation="Horizontal">
<Label Margin="0,0,5,0" Content="Animal Name" HorizontalAlignment="Left" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100" Height="25"></TextBox>
<Button Content="OK" Grid.Column="2" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="CarsTemplate">
<StackPanel Orientation="Horizontal">
<Label Margin="0,0,5,0" Content="Car Name" HorizontalAlignment="Left" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100" Height="25"></TextBox>
<Button Content="OK" Grid.Column="2" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<ListBox ItemsSource="{Binding Things}" SelectedItem="{Binding SelectedThing}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0" Orientation="Horizontal">
<TextBlock Padding="5" Text="{Binding Name}" Margin="0"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border Width="200">
<ContentControl Content="{Binding SelectedThing}">
<ContentControl.ContentTemplate>
<DataTemplate>
<ContentControl Name="cc"
Content="{Binding}"
ContentTemplate="{StaticResource PeopleTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Name}" Value="People">
<Setter TargetName="cc"
Property="ContentTemplate"
Value="{StaticResource PeopleTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Name}" Value="Animals">
<Setter TargetName="cc"
Property="ContentTemplate"
Value="{StaticResource AnimalsTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Name}" Value="Cars">
<Setter TargetName="cc"
Property="ContentTemplate"
Value="{StaticResource CarsTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Border>
</StackPanel>
<Grid>
Here is the Thing class:
public class Thing
{
public Thing(String name)
{
this.Name = name;
}
public String Name { get; set; }
public static ObservableCollection<Thing> GetThingList()
{
return new ObservableCollection<Thing>(new Thing[3] {
new Thing("People"),
new Thing("Animals"),
new Thing("Cars")
});
}
}

Related

Listbox DataTemplate to be applied to different models

I have two tables that contain just one value that is the key, too.
I created a list box to show it and modify it.
Table 1 is TTypes1 and the field is Type1 String
Table 2 is TTypes2 and the field is Type2 String
I've written this DataTemplate:
<DataTemplate x:Key="ListboxItems">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding}" />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<!-- edit to swap with save -->
<Button
Content=""
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="Save"
Visibility="{Binding IsVisible}" />
<!-- Cancel - visible only on edit -->
<Button
Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Delete -->
<Button
Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Add -->
<Button
Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
</StackPanel>
</Grid>
</DataTemplate>
Here are the list boxes but I'm not able to get it working as I want.
If I leave it like this:
<Label Grid.Column="0" Content="{Binding}" />
I do not see the text but the type TTypes1 or TTypes2.
But if I write:
<Label Grid.Column="0" Content="{Binding Type1}" />
Then I cannot use it on TType2 list box.
Here is where I use it:
<ScrollViewer
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
Margin="2"
AlternationCount="2"
BorderThickness="1"
ItemsSource="{Binding TTypes1}"
SelectedIndex="0"
SelectionMode="Single"
ItemTemplate="{StaticResource ListboxItems}"
Style="{StaticResource MahApps.Styles.ListBox.Virtualized}">
</ListBox>
</ScrollViewer>
and the second one is:
<ScrollViewer
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
Margin="2"
AlternationCount="2"
BorderThickness="1"
ItemsSource="{Binding TTypes2}"
SelectedIndex="0"
SelectionMode="Single"
ItemTemplate="{StaticResource ListboxItems}"
Style="{StaticResource MahApps.Styles.ListBox.Virtualized}">
</ListBox>
</ScrollViewer>
What am I missing?
Multiple Data Templates
The usual way to handle this is to create one distinct data template per type, e.g. for TType1 and TType2.
<DataTemplate x:Key="ListboxItemsTType1"
DataType="{x:Type local:TType1}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Content="{Binding Type1}" />
<!-- ...other markup. -->
</Grid>
</DataTemplate>
<DataTemplate x:Key="ListboxItemsTType2"
DataType="{x:Type local:TType2}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Content="{Binding Type2}" />
<!-- ...other markup. -->
</Grid>
</DataTemplate>
Reference the specific templates in your ListBoxes. You can also remove the x:Key from the data templates, so they are automatically applied to a matching type in the ListBox. This also works with mixed items in a list.
<ScrollViewer Grid.Row="0"
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
ItemTemplate="{StaticResource ListboxItems}"
...
</ListBox>
</ScrollViewer>
<ScrollViewer Grid.Row="1"
Margin="2"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListBox
...
ItemTemplate="{StaticResource ListboxItems}"
</ListBox>
</ScrollViewer>
Other Methods
If you really want to keep a single data template, you will have to switch the binding depending on the item type of the object bound as data context. There are multiple ways to achieve this.
Here is an example that uses a converter that converts an object to its type from a related question, copy it. A style for Label will use data triggers to apply the correct binding based on that type.
<local:DataTypeConverter x:Key="DataTypeConverter" />
<DataTemplate x:Key="ListboxItems">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0">
<Label.Style>
<Style TargetType="{x:Type Label}"
BasedOn="{StaticResource {x:Type Label}}">
<Setter Property="Content"
Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource DataTypeConverter}}"
Value="{x:Type local:TType1}">
<Setter Property="Content"
Value="{Binding Type1}" />
</DataTrigger>
<DataTrigger Binding="{Binding Converter={StaticResource DataTypeConverter}}"
Value="{x:Type local:TType2}">
<Setter Property="Content"
Value="{Binding Type2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<StackPanel Grid.Column="1"
Orientation="Horizontal">
<!-- edit to swap with save -->
<Button Content=""
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="Save"
Visibility="{Binding IsVisible}" />
<!-- Cancel - visible only on edit -->
<Button Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Delete -->
<Button Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
<!-- Add -->
<Button Click="LockUnlock_Click"
Content="{Binding Icon}"
ContentTemplate="{StaticResource IconPanelButton}"
DockPanel.Dock="Right"
Style="{StaticResource MahApps.Styles.Button.Flat}"
ToolTipService.ToolTip="{Binding ToolTip}" />
</StackPanel>
</Grid>
</DataTemplate>
Other options that completely rely on code, but are easier to reuse are:
Create a special value converter that does the same as the triggers, return a binding created in code with a property path that is based on type
Create a custom markup extension that automatically chooses the property path based on type
I do not provide examples on these options as they are complex and heavily depend on your requirements. Furthermore, I recommend the first approach to create multiple data templates, as this is the most favorable from a perspective of maintenance and flexibility in my opinion.
I think it is better to use ItemsControl.ItemTemplateSelector if you like two datatemplates.
First you need one class inherit class "DataTemplateSelector" and override its method to select which datatemplate to use.
public class ModelItemTemplateSelector: DataTemplateSelector
{
public DataTemplate Model1Template { get; set; }
public DataTemplate Model2Template { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if(item is Model1)
{
return Model1Template;
}
else if(item is Model2)
{
return Model2Template;
}
return base.SelectTemplate(item, container);
}
}
Then code in xaml is below
<ListBox ItemsSource="{Binding Source}">
<ListBox.ItemTemplateSelector>
<local:ModelItemTemplateSelector Model1Template="{StaticResource Model1Template}" Model2Template="{StaticResource Model2Template}" />
</ListBox.ItemTemplateSelector>
</ListBox>
And the other code:
Two datatemplates
<DataTemplate x:Key="Model1Template" DataType="{x:Type local:Model1}">
<TextBlock Text="{Binding Age}" />
</DataTemplate>
<DataTemplate x:Key="Model2Template" DataType="{x:Type local:Model2}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
Two types
public class BaseModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Model1 : BaseModel
{
private int age;
public int Age
{
get { return age; }
set
{
age = value;
this.RaisePropertyChanged(nameof(Age));
}
}
}
public class Model2 : BaseModel
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
this.RaisePropertyChanged(nameof(Name));
}
}
}
Source in vm
private ObservableCollection<BaseModel> source;
public ObservableCollection<BaseModel> Source
{
get { return source; }
set
{
source = value;
this.RaisePropertyChanged(nameof(Source));
}
}

Button in ListBox item's ItemsControl doesn't fire in WPF XAML

I've got the following setup for my ListBox in wpf:
ListBox with as ItemsPanel a StackPanel (orientation horizontal)
ItemTemplate of ListBox is a Grid with a TextBox and an ItemsControl
the Items control contains buttons with as ItemPanel a WrapPanel.
Somehow when I click on one of the buttons in the ItemsPanel, the ICommand wont fire in the ViewModel class which is bound to the View.xaml.
It looks like I'm selecting the ListBox item and not the item within the ItemsControl.
Here's the xaml code
<ListBox
Background="Transparent"
ItemTemplate="{StaticResource ProductGroupTemplate}"
FocusVisualStyle="{x:Null}"
VerticalContentAlignment="Top"
ItemsSource="{Binding NodeHeaders}"
Grid.Row="1"
Grid.ColumnSpan="3"
Grid.Column="0"
Grid.RowSpan="2"
SelectedItem="{Binding CurrentItem}"
BorderBrush="Transparent"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Margin="30,0,55,0"
VerticalAlignment="Top">
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding HasParent}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
And the DataTemplate
<DataTemplate x:Key="ProductGroupTemplate">
<Grid Margin="0,0,20,0">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Description}" FontSize="20" Grid.Row="0" Grid.Column="0" Foreground="{StaticResource DefaultLabelColor}" />
<ItemsControl ItemsSource="{Binding Nodes}" Grid.Row="1" Grid.Column="0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Text="{Binding Description}" Height="75" Width="150" Padding="5" Margin="5" Background="{StaticResource SalesItemsBackground}"
Foreground="{StaticResource SalesItemsForeground}" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Left" Command="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ContentControl}},
Path=DataContext.Select}" CommandParameter="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
If you have a view model that declares an ICommand instance and is set as the DataContext of a view (UserControl, or Window), then you can use that property to access your ICommand instance. From the Button in your DataTemplate, you can use this RelativeSource Binding:
<Button Text="{Binding Description}" Height="75" Width="150" Padding="5" Margin="5"
Background="{StaticResource SalesItemsBackground}" TextAlignment="Left"
Foreground="{StaticResource SalesItemsForeground}" HorizontalAlignment="Center"
VerticalAlignment="Center" Command="{Binding DataContext.Select, RelativeSource={
RelativeSource AncestorType={x:Type YourViewsPrefix:YourView}}}"
CommandParameter="{Binding}"/>
That's because your data template's DataContext is set to an item from the listbox. If you have List<Person> bound to your list box every list box item's DataContext would be a Person which is why you can write something like "{Binding Description}". You have two ways to execute a command from DataTemplate one of them is the one that "Sheridan" told you. As an alternative you could set your element's DataContext to your parent View or ViewModel.
<DataTemplate>
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type View/ViewModel}}">
</Grid>
</DataTemplate>

WPF Xaml converter Error

I am getting a compilation error as
Error 1 The type or namespace name 'Converters' could not be found (are you missing a using directive or an assembly reference?) G:\C#\Practice\DataGrid\DataGrid\obj\x86\Debug\MainWindow.g.cs 12 7 DataGrid
Below is my Xaml code, I am new to WPF please help me out. I have the converter Class.
<Window x:Class="DataGrid.MainWindow "
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="500" Width="700"
xmlns:c="clr-namespace:Converters">
<Window.Resources>
<c:BoolToStringConverter x:Key="BoolToStringConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="59*" />
<RowDefinition Height="402*" />
</Grid.RowDefinitions>
<StackPanel Margin="0,55,0,0" Grid.RowSpan="2">
<DataGrid ItemsSource="{Binding Path=Courses}" AutoGenerateColumns="False" HorizontalAlignment="Left" Name="datagrid1" CanUserAddRows="False" HeadersVisibility="Column" RowDetailsVisibilityMode="Visible" VerticalScrollBarVisibility="Auto" CanUserSortColumns="True" CanUserResizeColumns="False" Height="339" Width="610">
<DataGrid.Resources>
<Style TargetType="{x:Type CheckBox}" x:Key="DataGridCheckBox">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="IsEnabled" Value="True" />
<Setter Property="Margin" Value="4" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Course Title" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Code}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Course Description" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Descrption}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Required" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=IsRequired, Converter={StaticResource BoolToStringConverter}}"
VerticalAlignment="Center" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
<StackPanel Margin="0,0,539,32">
<TextBlock Text="Select Enroolment:" FontSize="15"
Height="26"
Grid.RowSpan="1"
Width="134">
</TextBlock>
</StackPanel>
<TextBlock DockPanel.Dock="Left"
HorizontalAlignment="Left"
Text="Select Course:"
Width="139" FontSize="15"
Margin="0,32,0,0">
</TextBlock>
<ComboBox HorizontalAlignment="Right"
Margin="0,0,69,33"
Name="comboBox1"
Width="476"
Height="23"
VerticalAlignment="Bottom" />
</Grid>
xmlns:c="clr-namespace:Converters"
You should check the namespace of your Converters class, that is what you should put in place of Converters. If Converters is your class, then you should put whatever it says after namespace in your .cs file.
Example:
namepsace MyNamespace {
public class Converters { }
}
Then your XAML would be:
xmlns:c="clr-namespace:MyNamespace"
Extra:
If you want to be more specific, you can add the assembly parameter as well.
xmlns:window="clr-namespace:MyNamespace;assembly=MyNamespace"
Where Assembly can be found in your Build Properties (Right-click Project, Properties, Application, Assembly Information)
Your default namespace can also be found in the Build Properties as well.

Textbox inside listbox selecteditem.. how modify textbox content?

I have a listbox for inventory. When I select an item it shows a couple of controls to edit the volume or amount of items. like this:
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" >
<Label Content="Edit Volume:"/>
<Button Click="bPlus_Click2" Content="+" Height="29" Margin="10,0,0,0" Name="bPlus" Width="29" />
<TextBox FontSize="16" Height="29" HorizontalContentAlignment="Center" IsReadOnly="True" Name="tNum2" Text="0" VerticalContentAlignment="Center" Width="44" />
<Button Click="bMinus_Click2" Content="-" Height="29" Name="bMinus" Width="29" />
<Button Content="OK!"/>
<StackPanel.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}}}" Value="False">
<Setter Property="StackPanel.Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
Now I need the PLUS and MINUS buttons to edit the content of the textbox.. how can i do it??
I FOUND THE WAY!!
THIS IS WHAT I HAVE:
<Window.Resources>
<DataTemplate x:Key="dtInventory">
<Border Name="itemBorder" BorderBrush="#FFEBE476" BorderThickness="2" Padding="10" Margin="2" Background="#FF5AB11D">
<StackPanel x:Name="sp1">
<StackPanel Orientation="Horizontal" x:Name="spsp1">
<StackPanel Width="60">
<TextBlock Text="DME Item: "/>
</StackPanel>
<StackPanel Width="205" x:Name="spsp2">
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
<StackPanel Width="60" x:Name="spsp3">
<TextBlock Text="Volume: "/>
</StackPanel>
<StackPanel Width="30" x:Name="spsp4">
<TextBlock Text="{Binding Path=Volume}"/>
</StackPanel>
</StackPanel>
<StackPanel x:Name="sp2" HorizontalAlignment="Right" Orientation="Horizontal" >
<Label Content="Edit Volume:" x:Name="l1"/>
<myext:IntegerUpDown x:Name="udVolume" Minimum="0" DefaultValue="0"/>
<Button Content="OK!" x:Name="bOk" Click="bOk_Click" />
<StackPanel.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}}}" Value="False">
<Setter Property="StackPanel.Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</Window.Resources>
Then the Listbox:
<ListBox Height="399" HorizontalAlignment="Left" Margin="462,61,0,0" Name="lInventory" VerticalAlignment="Top" Width="390" ItemsSource="{Binding}" ItemTemplate="{StaticResource dtInventory}">
And the .cs:
ListBoxItem selecteditem = lInventory.ItemContainerGenerator.ContainerFromIndex(int.Parse(lInventory.SelectedIndex.ToString())) as ListBoxItem;
if (selecteditem != null)
{
try
{
DataTemplate dt = selecteditem.ContentTemplate;
Border border = VisualTreeHelper.GetChild(selecteditem, 0) as Border;
ContentPresenter cp = border.Child as ContentPresenter;
StackPanel sp = dt.FindName("sp1", cp) as StackPanel;
IntegerUpDown updown = sp.FindName("udVolume") as IntegerUpDown;
if (updown.Value != 0)
{
Inventory.DMEItems dme = new Inventory.DMEItems();
dme.Volume = int.Parse(updown.Value.ToString());
dme.DMEInventoryItemID = int.Parse(lInventory.SelectedValue.ToString());
dme.UpdateItem();
UpdateInventory();
}
}
catch (Exception ex)
{ System.Windows.MessageBox.Show("ERROR: " + ex.Message, "Edit Volume" ,MessageBoxButton.OK, MessageBoxImage.Error); }
}
I hope it works for other people!
Unfortunately you can't do Mathematic oeprations in xaml out of the box.
But you could use a Numeric UpDown control (e.g. from the Extented WPF Toolkit)
Or you make your own UserControl where you have your two buttons and your textbox along with the functionality to count up/down.
Then use that control in your markup e.g.
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" >
<Label Content="Edit Volume:"/>
<local:MyNumericUpDownControl/>
EDIT:
Here's a link on how to create your own numericupdown control

davidpoll's printcollection

I'm trying to use David Poll's printcollection control, from the SLaB project- www.davidpoll.com but for some reason no items get shown. Maybe it's something with my itemtemplate, please have a look at this:
<Style x:Key="PrintStyle"
TargetType="SLaB:CollectionPrinter">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<sdk:Label x:Name="lblTitle" HorizontalAlignment="Left" Margin="0,8,0,0" VerticalAlignment="Top" Content="{Binding Source={StaticResource ResourceWrapper}, Path=NoteEditorResources.Title}"/>
<sdk:Label x:Name="lblTitleResult" HorizontalAlignment="Left" Margin="42,8,0,0" VerticalAlignment="Top" Content="{Binding Path=Title}"/>
<sdk:Label x:Name="lblDateCreated" HorizontalAlignment="Right" Margin="0,8,156,0" VerticalAlignment="Top" Content="{Binding Source={StaticResource ResourceWrapper}, Path=NoteEditorResources.DateCreated}"/>
<sdk:Label x:Name="lblDateCreatedResult" HorizontalAlignment="Right" Margin="0,8,113,0" VerticalAlignment="Top" Content="{Binding Path=DateCreated}"/>
<RichTextBox x:Name="rtbContent" Margin="0,28,0,8" Width="582" Xaml="{Binding Content}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch">
<StackPanel HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock Text="{Binding CurrentPage, StringFormat='{}Page {0} '}" />
<TextBlock Text="{Binding PageCount, StringFormat='{}/ {0}'}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="FooterTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel HorizontalAlignment="Center"
Orientation="Horizontal">
<TextBlock Text="{Binding FirstItemValue.Name}" />
<TextBlock Text=" - " />
<TextBlock Text="{Binding LastItemValue.Name}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I've used his printing control, but I never modified the itemtemplate. I used his TestPrinter.xaml as a template and filled in the HeaderTemplate, FooterTemplate, and the BodyTemplate with my code.
The BodyTemplate being the important one to take a look at. Here is the BodyTemplate section from his example:
<Printing:CollectionPrinter.BodyTemplate>
<DataTemplate>
<sdk:DataGrid ItemsSource="{Binding CurrentItems}"
AutoGenerateColumns="False"
VerticalScrollBarVisibility="Disabled">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding Name}"
Header="Name" />
<sdk:DataGridTextColumn Binding="{Binding Address}"
Header="Address" />
<sdk:DataGridTextColumn Binding="{Binding Age}"
Header="Age" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</DataTemplate>
</Printing:CollectionPrinter.BodyTemplate>
The important thing is to set the CurrentItems as the source for your control that will be used to display your collection. This way it can automatically calculate how many items to display in the page before they cut off.

Resources