how to access TextBox inside ListBox itemsSource which is Datatemplate? - c#

I have a ListBox and its ItemsSource is linked with a ComboBox SelectedItem. Its template is associated with a DataTemplate. Everything is fine but how to access each TextBox inside ListBoxItems. I have 5 labels and 2 TextBoxes inside each ListItem. I want to access each and every TextBox and labels inside ListBoxItem. I need some idea how to access each TextBox inside each Item. For example, there is "wbprofileDesc" TextBox in first ListBoxItem. So I need to access this TextBox and write some functionality to it like keypress event. It need to work for each and every TextBox inside all the ListBoxItems individually. Assume there are 5 ListBoxItems. Also I need to fetch other controls also like wbselect(ComboBox), wbdepth, wbwidthvalue and etc. I am using MVVM model for this.
<Window.Resources>
<local:wbItemViewModel x:Key="wbItem"/>
<DataTemplate x:Key="wbObjectsDataTemplate">
<Grid Grid.ColumnSpan="1" Grid.RowSpan="1" Height="Auto" Width="642" Margin="0,0,0,-14">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Width="697" Margin="10,0,0,0" Height="54" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="49*"/>
<ColumnDefinition Width="91*"/>
<ColumnDefinition Width="309*"/>
<ColumnDefinition Width="306*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition/>
<RowDefinition Height="auto" MinHeight="5"/>
</Grid.RowDefinitions>
<Label Content="{Binding WBName_lbl}" Margin="0,3,0,5" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"/>
<ComboBox x:Name="wbselect" Margin="5,0,10,1" Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="0">
<ComboBoxItem x:Name="wbstraight" IsSelected="True" Content="straight"/>
<ComboBoxItem x:Name="wbtapered" Content="tapered"/>
</ComboBox>
<!--KeyDown="{Binding Path=profileDesc}"-->
<!-- KeyDown="profileDesc_KeyDown" -->
<TextBox x:Name="wbprofileDesc" Margin="18,0,20,1" Grid.Column="2" Grid.Row="0" GotFocus="wbprofileDesc_GotFocus"/>
<TextBox x:Name="wbdepth" Text="{Binding ElementName=wbwidthvalue, Path=Content, Mode=OneWay}" Margin="10,0,73,1" Grid.Column="3" Grid.Row="0"/>
<Label x:Name="wbwidthvalue" Margin="10,0,190,5" Grid.Column="2" FontSize="8" Grid.Row="1"/>
<Label x:Name="wbthicknessvalue" Margin="118,0,82,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wblengthvalue" Margin="208,0,0,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wbnexwidthvalue" Margin="10,0,178,5" FontSize="8" Grid.Row="1" Grid.Column="3"/>
<Label x:Name="wbdepthvalue" Grid.Row="1" Grid.Column="3" FontSize="8" Margin="132,0,31,5"/>
<!--<Label x:Name="totalvalue" Margin="30,10,24,16" Grid.Row="3" Grid.Column="3"/>-->
</Grid>
</Grid>
</DataTemplate>
</Window.Resources>
<ListBox x:Name="wbListDataTemplate"
ItemsSource="{Binding wbVisibleItems}"
ItemTemplate="{DynamicResource wbObjectsDataTemplate}"
DataContext="{DynamicResource wbItem}"
Background="{x:Null}"
SelectedItem="{Binding wbSelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsSynchronizedWithCurrentItem="True"
Canvas.Top="51" Height="222" Width="686"/>

Here is an example of you could find the controls in the DataTemplate inside the event handler:
private void wbprofileDesc_GotFocus(object sender, RoutedEventArgs e)
{
TextBox wbprofileDesc = sender as TextBox;
Grid parentGrid = wbprofileDesc.Parent as Grid;
ComboBox wbselect = parentGrid.Children.OfType<ComboBox>().FirstOrDefault(x => x.Name == "wbselect");
Label wbwidthvalue = parentGrid.Children.OfType<Label>().FirstOrDefault(x => x.Name == "wbwidthvalue");
}

Related

Filter in binding to CollectionViewSource in WPF

I'm doing some fixes in a project where I need to edit an entity named Tariff, which have as a property a collection of TariffSteps. The model was made with Entity Framework Code First:
namespace pbxControl.model.Classes
{
public class Tariff : PropertyChangedNotifier
{
public int TariffId { get; set; }
public string Description { get; set; }
// ...
public ObservableCollection<TariffStep> TariffSteps { get; set; }
// ...
}
public class TariffStep : PropertyChangedNotifier
{
public int TariffStepId { get; set; }
[DefaultValue(0)]
public int Duration { get; set; }
// ...
#region references
public virtual ObservableCollection<Tariff> Tariffs { get; set; }
// ...
Which created a many to many relationship in the DB through an intermediate table "TariffStepTariffs".
In the UI the interface is based in a master - detail scenario where an outer grid is binded to a CollectionViewSource (on tariff collection), inside that grid there is a Datagrid where the tariffs are shown (master), and another grid where the selected tariff is detailed.
Originally, before the new fixes were implemented, the way of dealing with the tariffSteps was as follow: an area for add / remove/ modify TariffSteps in the Model (TariffStepsGrid), and another area where the client could add tariffSteps from the first area to a Tariff (TariffTariffStepsGrid). The idea was that several tariff could share the same step if they have the same properties:
previous way of assign tariffSteps to tariff
<TabItem Name="Tariff_Tab" HorizontalAlignment="Left" TabIndex="5" Header="Tarifas" Style="{StaticResource HorizontalTab}">
<Grid x:Name="TariffsGrid" DataContext="{Binding Source={StaticResource tariffViewSource}}">
<Grid x:Name="TariffDetailGrid" Grid.Row="0" Grid.Column="0" DataContext="{Binding}">
<Grid x:Name="TariffDetailPropertiesGrid" Grid.Row="0" Grid.Column="0" DataContext="{Binding}">
<!-- Some controls for properties of the Tariff -->
</Grid>
<Grid x:Name="CurrencyGrid" Grid.Row="0" Grid.Column="1" DataContext="{StaticResource currencyViewSource}">
<!-- This grid is for management of another entity (Currency) -->
</Grid>
<Grid Grid.Row="1" Grid.Column="0" x:Name="TariffTariffStepsGrid" HorizontalAlignment="Right">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="360"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<Grid x:Name="TariffTariffStep" Grid.Column="0" DataContext="{Binding Path=TariffSteps}" HorizontalAlignment="Right">
<ListBox x:Name="TariffStepList1" ItemsSource="{Binding}" HorizontalAlignment="Right" VerticalAlignment="Top"
VerticalContentAlignment="Center" HorizontalContentAlignment="Left" Height="130" Width="200" Margin="0 15 0 5"
TabIndex="22">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="2 2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=DurationV, Mode=TwoWay}" Grid.Column="0" Width="60" TextAlignment="Left"/>
<TextBlock Text="{Binding Path=PeriodV, Mode=TwoWay}" Grid.Column="1" Width="60" TextAlignment="Center"/>
<TextBlock Text="{Binding Path=CostV, Mode=TwoWay}" Grid.Column="2" Width="60" TextAlignment="Right"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<Grid x:Name="TariffTariffStepsButtons" Grid.Column="1">
<Grid Height="50">
<Button x:Name="TariffTariffStepAdd" HorizontalAlignment="Center" VerticalAlignment="Top"
Click="TariffTariffStepAdd_Click" Background="Transparent" Style="{StaticResource LessThanButton}">
</Button>
<Button x:Name="TariffTariffStepRemove" HorizontalAlignment="Center" VerticalAlignment="Bottom"
Click="TariffTariffStepRemove_Click" Background="Transparent" Style="{StaticResource GreaterThanButton}">
</Button>
</Grid>
</Grid>
</Grid>
<Grid x:Name="TariffStepsGrid" Grid.Row="1" Grid.Column="1" DataContext="{StaticResource tariffStepViewSource}">
<!-- Some controls for properties of the TariffStep and buttons for add / remove a TariffStep -->
<ListBox x:Name="TariffStepList" ItemsSource="{Binding}" HorizontalAlignment="Right" VerticalAlignment="Top"
VerticalContentAlignment="Center" HorizontalContentAlignment="Left" Height="130" Width="200" Margin="0 15 20 5"
SelectionChanged="TariffStep_SelectionChanged" GotFocus="TariffStepList_GotFocus" TabIndex="22">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="2 2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=DurationV, Mode=TwoWay}" Grid.Column="0" Width="60" TextAlignment="Left"/>
<TextBlock Text="{Binding Path=PeriodV, Mode=TwoWay}" Grid.Column="1" Width="60" TextAlignment="Center"/>
<TextBlock Text="{Binding Path=CostV, Mode=TwoWay}" Grid.Column="2" Width="60" TextAlignment="Right"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
<Grid x:Name="TariffActionGrid" Grid.Row="1" Grid.Column="0"><!-- Buttons for save, etc. --> </Grid>
<Grid x:Name="AllTariffsGrid" Grid.Row="2" Grid.Column="0" VerticalAlignment="Top" Grid.ColumnSpan="2">
<DataGrid x:Name="ListTarif1" HorizontalAlignment="Right" Height="255" VerticalAlignment="Top" AutoGenerateColumns="False"
ItemsSource="{Binding}" Width="760" Margin="20,25,20,0" SelectionChanged="ListTarif1_SelectionChanged"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="DescripciĆ³n" Binding="{Binding DescriptionV, Mode=TwoWay}" IsReadOnly="True" Width="152"/>
<DataGridTextColumn Header="Fecha de Inicio" Binding="{Binding StartDateV}" IsReadOnly="True" Width="152"/>
<DataGridTextColumn Header="Fecha Final" Binding="{Binding EndDateV}" IsReadOnly="True" Width="152"/>
<DataGridTextColumn Binding="{Binding CurrencyV.Code}" Header="Moneda" IsReadOnly="True" Width="152"/>
<DataGridTextColumn Binding="{Binding InitialCostV}" IsReadOnly="True" Width="152">
<DataGridTextColumn.Header>
<AccessText TextWrapping="WrapWithOverflow" Width="100" TextAlignment="Center">Costo Inicial</AccessText>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</TabItem>
For populating the TariffStepList listbox (the one for the collection of all tariffs) in code behind was implemented a filter that allowed in the view of the tariffStepViewSource only the tariffsteps that were not already assigned to the tariff:
public void TariffStepsNonInTariffFilter(object sender, FilterEventArgs e)
{
TariffStep tariffStep = e.Item as TariffStep;
var Tariff = ListTarif1.SelectedItem as Tariff;
if (Tariff != null)
{
if (tariffStep.Tariffs.Contains(Tariff))
{
e.Accepted = false;
return;
}
}
e.Accepted = true;
}
That filter was assigned to the tariffStepViewSource only when the app has the Tariff tab on focus, when the focus were to another tab, it was unasigned.
Well, all that worked like a charm, but in the new design there was no need for the tariffStepViewSource because the tariffSteps were assigned directly to the tariff (it didn't matter that they were repeated in the database). As can be seen in the following xaml, the binding is to the collection of tariffSteps of the tariff ( DataContext="{Binding Path=TariffSteps} ).
<TabItem Name="Tariff_Tab" HorizontalAlignment="Left" TabIndex="5" Header="Tarifas" Style="{StaticResource HorizontalTab}">
<Grid x:Name="TariffsGrid" DataContext="{Binding Source={StaticResource tariffViewSource}}">
<Grid x:Name="TariffDetailGrid" Grid.Row="0" Grid.Column="0" DataContext="{Binding}">
<!-- grids & controls for properties of the Tariff & the Currency entity -->
<Grid x:Name="TariffTariffStepsGrid" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"
DataContext="{Binding Path=TariffSteps}">
<TextBox x:Name="TariffStepCost" HorizontalAlignment="Right" VerticalAlignment="Top" VerticalContentAlignment="Center"
HorizontalContentAlignment="Right" Margin="0,115,225,0" Height="25" Width="100"
Text="{Binding Path=CostV, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=N2}"
LostFocus="TariffStepCost_LostFocus" TabIndex="21"
IsEnabled="{Binding DataContext.Source.Count, Converter={StaticResource IsEnabledBySourceCountConverter},
RelativeSource={RelativeSource Self}}"/>
<Label x:Name="TariffStepCostlabel" Height="25" Content="Costo:" Margin="0,115,325,0" VerticalAlignment="Top"
VerticalContentAlignment="Center" HorizontalAlignment="Right" HorizontalContentAlignment="Left" Width="55" Padding="0"/>
<!-- Some more controls for other properties of the TariffStep and buttons for add / remove a TariffStep -->
<ListBox x:Name="TariffStepList1" ItemsSource="{Binding Path=TariffSteps}" HorizontalAlignment="Right" VerticalAlignment="Top"
VerticalContentAlignment="Center" HorizontalContentAlignment="Left" Height="130" Width="200" Margin="0 15 20 5"
TabIndex="22">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="2 2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=DurationV, Mode=TwoWay}" Grid.Column="0" Width="60" TextAlignment="Left"/>
<TextBlock Text="{Binding Path=PeriodV, Mode=TwoWay}" Grid.Column="1" Width="60" TextAlignment="Center"/>
<TextBlock Text="{Binding Path=CostV, Mode=TwoWay}" Grid.Column="2" Width="60" TextAlignment="Right"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
<!-- TariffActionGrid && AllTariffsGrid -->
</Grid>
</TabItem>
The fact is that, no matter what I do, if I remove the filter from code behind, in the listbox "TariffStepList1" nothing get shown. I can add new tariffSteps and save the context, but when I close the app and open it again, nothing is shown. I've tested all option, even creating new ListBox, button, etc. in a different tab. I have checked that there is no remaining references to tariffStepViewSource in the whole project, still there is no way the tariffSteps get shown.
In another tab I have the same xaml controls structure in which a navigation property is modified with exactly the same master - detail scenario (an entity named Extension which have a collection of associated email addresses), and there is no problem there. As soon as I re-incorporate the tariffStepViewSource, with it corresponding filter, the tariffSteps get shown, even when there binding in the Grid is not to the viewsource.

WPF TextBox not trimming in DataTemplate

I have an odd problem with TextBox with TextTrimming set to CharacterElipsis used in a DataTemplate in WPF application. At the start of application everything works fine. But when I am resizing the window - reducing the width, the trimming is not working.
In an example below:
<Grid>
<DockPanel>
<DockPanel.Resources>
<DataTemplate x:Key="lowerLevel" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="34*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="14*" />
</Grid.ColumnDefinitions>
<TextBlock Text="textboxvalue1" Grid.Column="0" FontWeight="Bold" VerticalAlignment="Center" Margin="15,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue2" Grid.Column="1" FontWeight="Bold" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue3" Grid.Column="2" FontWeight="Bold" VerticalAlignment="Center" Margin="0,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<CheckBox IsChecked="True" Content="ApprovedText" FontWeight="Bold" Grid.Column="3" VerticalAlignment="Center" Margin="0,10,15,10" />
</Grid>
</DataTemplate>
</DockPanel.Resources>
<ListView x:Name="listViewControl" ItemTemplate="{StaticResource lowerLevel}" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
</DockPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="34*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="14*" />
</Grid.ColumnDefinitions>
<TextBlock Text="textboxvalue1" Grid.Column="0" FontWeight="Bold" VerticalAlignment="Center" Margin="15,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue2" Grid.Column="1" FontWeight="Bold" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue3" Grid.Column="2" FontWeight="Bold" VerticalAlignment="Center" Margin="0,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<CheckBox IsChecked="True" Content="ApprovedText" FontWeight="Bold" Grid.Column="3" VerticalAlignment="Center" Margin="0,10,15,10" />
</Grid>
</Grid>
I am having two identical Grids, but first one is placed in a DataTemplate and the second is just a separate control. TextBoxes in bottom grid are trimming correctly, when resizing window, however the TextBoxes from DataTemplate do not fit the width of parent columns while window resizing.
The code behind is:
public partial class MainWindow : Window
{
private ListCollectionView comparedFamiliesView;
public ListCollectionView ComparedFamiliesView
{
get
{
if (comparedFamiliesView == null)
{
comparedFamiliesView = new ListCollectionView(new List<Object>() { new Object(), new Object(), new Object() });
}
return comparedFamiliesView;
}
}
public MainWindow()
{
InitializeComponent();
listViewControl.ItemsSource = ComparedFamiliesView;
}
}
It basically adds three objects to have something to view on ListView.
I was trying different combinations of VerticalAlignment, VerticalContentAlignment - didn't work.
What I have tried was to place each TextBox in separate Grid in order to bind its Width to TextBox Width or MaxWidth, like:
<Grid Grid.Column="0" x:Name="grid1">
<TextBlock Text="textboxvalue1" FontWeight="Bold" VerticalAlignment="Center" Margin="15,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" MaxWidth="{Binding ActualWidth, ElementName=grid1}" />
</Grid>
Didn't work either.
How can I force TextBoxes in DataTemplate to behave the same way as those in separate Grid?
Or what am I doing wrong with TextTrimming when using in DataTemplate.
Thank you for your help!!!
Regards,
Ariel
Try to set the ScrollViewer.HorizontalScrollBarVisibility attached property of the ListView to Disabled:
<ListView x:Name="listViewControl" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ...

Getting id from selected listview item

I have a ListView containing this data template:
<ListView x:Name="lvRitten" Grid.Column="0" Background="Gold" ItemsSource="{Binding ObcRitten}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionChanged="lvRitten_SelectionChanged" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type classes:Rit}">
<Button x:Name="btnride" Height="100" Width="132" >
<StackPanel>
<Grid Height="100" Width="132">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.ColumnSpan="2" Background="Aquamarine">
<Label Content="naam"/>
</Grid>
<Grid Grid.Column="0" Grid.Row="1" Background="AntiqueWhite">
<StackPanel>
<Label Content="{Binding id}" FontSize="10"/>
<Label Content="{Binding Naam}" FontSize="10"/>
<Label Content="{Binding AantalPassagiers}" FontSize="10"/>
<Label Content="{Binding TaxiNummer}" FontSize="10"/>
</StackPanel>
</Grid>
<Grid Grid.Column="1" Grid.Row="1">
</Grid>
</Grid>
</StackPanel>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
but now I want to get the id that's in the first label in the 3rd grid when I click on a ListViewItem.
What is the easiest way to get the id?
Can I use binding to bind the id to a other label?
Or do I need to do something else?
ObcRitten is a public ObservableCollection and is filled with Rit
example of a Rit
Rit rit1 = new Rit
{
id = 20,
AantalPassagiers = 5,
Naam = "Jan",
TaxiNummer = 1
};
all elements inside DataTemplate share the same DataContext, namely Rit item. To display id twice in different places you need to create two labels, and bind both to id
<Grid Grid.Column="1" Grid.Row="1">
<Label Content="{Binding id}" FontSize="10"/>
</Grid>
outside of ListView bind to ListView.SelectedItem:
<Label Content="{Binding SelectedItem.id, ElementName=lvRitten}" FontSize="10"/>
Create new property in your ViewModel:
public Rit SelectedRit {get; set;}
Then bind this property with ListView:
<ListView SelectedItem = "{Binding SelectedRit}"..../>
You could cast the SelectedItem property to a Rit and access the id property:
Rit rit = lvRitten.SelectedItem as Rit;
if (rit != null)
var id = rit.id;
You could also bind it directly to a TextBlock like this:
<TextBlock Text="{Binding SelectedItem.id, ElementName=lvRitten}" />

TabItem DataTemplate with binding

I have a TabControl in my app. I'd like to have as many TabItems as many entries are in my dictionary.
Here's my dictionary:
public Dictionary<string , ObservableCollection<PerformanceCounter>> Counters
{
get { return _Counters; }
}
Dictionary<string, ObservableCollection<PerformanceCounter>> _Counters = new Dictionary<string , ObservableCollection<PerformanceCounter>>();
Every entry has a string key and ObservableCollection of PerformanceCounter objects. Important thing is the fact that every PerformanceCounter object has properties: CounterName and InstanceName - I'll need these two to display them.
Now, to my XAML:
<TabItem Header="Memory">
<Grid Name="RAMGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Name="RAMListBox" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" ItemsSource="{Binding Memory, Mode=OneWay}" SelectionMode="Multiple" BorderThickness="1" BorderBrush="#FF8B8B8B" SelectionChanged="RAMListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding CounterName, Mode=OneWay}" />
<Run Text="{Binding InstanceName, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1" Click="RAMSelectAllButton_Click" >
<TextBlock Text="SELECT ALL"/>
</Button>
<Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" Click="RAMUnSelectAllButton_Click" >
<TextBlock Text="UNSELECT ALL"/>
</Button>
</Grid>
</TabItem>
That's what I did and, as you might already know, it does not work. The above code is only for one entry of my dictionary, where the key is "Memory".
In my code I set DataContext:
this.DataContext = appData.Counters;
appData.Counters is that dictionary I presented at the beginning.
Here's what I'd like to achieve:
No matter how many entries there are in my dictionary, my TabControl would display TabItem for each of them.
Each TabItem has a ListBox and 2 buttons. I'll need too be able to access those (in order to clear the list and to have click event for each button).
I really don't know how to do it, I hope you can help me out.
Binding TabControl to items in Dictionary:
<Window.Resources>
<DataTemplate x:Key="templateForTheContent" >
<StackPanel>
<ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
ItemsSource="{Binding Value, Mode=OneWay}"
SelectionMode="Multiple"
BorderThickness="1" BorderBrush="#FF8B8B8B">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding CounterName, Mode=OneWay}" />
<Run Text="{Binding InstanceName, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" >
<TextBlock Text="{Binding Key}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl TabStripPlacement="Left" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch"
ItemsSource="{Binding Counters}"
ContentTemplate="{StaticResource templateForTheContent}"
ItemTemplate="{StaticResource templateForTheHeader}">
</TabControl>
</Grid>
Now, Dictionary is not observable so if items will be added/removed during runtime, you may consider using something like ObservableDictionary instead
Create a ViewModel-class containing:
your Dictionary
two ICommand-Implementations for your Buttons
then
set the ViewModel-class as DataContext of the TabControl
set Counters as the ItemSource of the TabControl
reuse your XAML-Code defined within the TabItem and use it as
the Tabcontrol.ContentTemplate
Bind .Command of your Buttons to the ICommands in your ViewModel using RelativeSource
see for samples:
ContentTemplate: https://wpf.2000things.com/tag/tabcontrol/
ICommand https://stackoverflow.com/a/1468830/4919708
RelativeSource: https://stackoverflow.com/a/84317/4919708
As i said in one of the comments above I changed my Dictionary to this:
//list of all counters
public ObservableCollection<ObservableCollection<PerformanceCounter>> Counters
{
get { return _Counters; }
}
ObservableCollection<ObservableCollection<PerformanceCounter>> _Counters = new ObservableCollection<ObservableCollection<PerformanceCounter>>();
i used #Arie's solution to write this XAML:
<DataTemplate x:Key="templateForTheContent" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
ItemsSource="{Binding}"
SelectionMode="Multiple"
BorderThickness="1" BorderBrush="#FF8B8B8B">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding CounterName, Mode=OneWay}" />
<Run Text="{Binding InstanceName, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1" >
<TextBlock Text="SELECT ALL"/>
</Button>
<Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" >
<TextBlock Text="UNSELECT ALL"/>
</Button>
</Grid>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" >
<TextBlock Text="{Binding CategoryName}"/>
</DataTemplate>
</Window.Resources>
It displays correctly as many Tabs as I add entries to my Class ObservableCollection in the code behind.
Now i have a new problem: I don't know how to access each listBox from each Tab. i need to be able to read the list of selected objects.

Checkbox in ItemTemplate

I have a <Checkbox/> in my <GridView.ItemTemplate>. How do I handle the <Checkbox/> as to the element in which it is?
For example, I want to delete item when checkbox checked.
I think should write here. But what?
private void CheckBox_Checked_1(object sender, RoutedEventArgs e)
{
}
Here's My XAML:
<GridView Margin="0,10,0,0"
RelativePanel.AlignHorizontalCenterWithPanel="True"
x:Name="GridColections"
IsItemClickEnabled="True"
SelectionMode="None"
ItemsSource="{x:Bind DS.AllRem, Mode=OneWay}"
ItemClick="GridColections_ItemClick" >
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:GetRem" >
<Grid Margin="-2,0,-6,0" BorderBrush="LightGray" BorderThickness="1" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap" Text="{x:Bind ReminderName}" Margin="5,5,0,0" FontSize="20"/>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="1" Width="600" TextWrapping="Wrap" Text="{x:Bind ReminderDescription}" Margin="5,5,0,0" FontSize="12"/>
<CheckBox Grid.Column="2" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Center" Checked="CheckBox_Checked_1"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The problem is that you almost certainly want to be able to use the DataContext in your click handler but you won't get that easily by just having a reference to the CheckBox which will be the sender argument in your callback. Normally what you would do here is create a Command on your item's view model and bind to that and any additional information that you would want to pass in you would pass in through the CheckBox's CommandParameter.
Once you do this you are now operating in your view model with a reference to whatever piece of information that you need through the command parameter (for instance you could set CommandParameter = "{Binding}" to pick up the entire data context which would be the item's view model and that would be accessible from your Command as an argument to it). You should be able to solve your issue this way.

Categories