Binding ListBox inside a listBox WP8 - xaml

I need to bind a a listbox named cityListBox inside the ContryListBox with the following structure of class
public class Country
{
public Country();
public string ID { get; set; }
public List<City> LstCity { get; set; }
public string Title { get; set; }
}
i want that my outer listbox should come with Country Title as header and in the innner listBox City header where city is also a class with Id and Title
my xaml code:
<ListBox x:Name="ContryListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Bewise:ExpanderControl HeaderText="{Binding Title, Mode=OneWay}" >
<Bewise:ExpanderControl.ContentArea>
<ListBox x:Name="cityListBox " >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox></CheckBox>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Bewise:ExpanderControl.ContentArea>
</Bewise:ExpanderControl>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

<!--Added ItemsSource binding-->
<ListBox x:Name="ContryListBox" ItemsSource="{Binding YourCountryListProperty}>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Bewise:ExpanderControl HeaderText="{Binding Title, Mode=OneWay}" >
<Bewise:ExpanderControl.ContentArea>
<!--Added ItemsSource Binding-->
<ListBox x:Name="cityListBox" ItemsSource="{Binding LstCity}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox></CheckBox>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Bewise:ExpanderControl.ContentArea>
</Bewise:ExpanderControl>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Related

Binding IsSelected on ListViewItem not working for me in UWP application

I'm working with a list of objects that have a Selected property and I'm trying to bind it to the IsSelected property on ListViewItem within a multi-select ListView control in UWP.
I just can't seem to get the binding to work. The checkboxes in the ListView do not render checked if Selected = True and the Set on Selected never gets triggered when checking an item.
SettingsPage.xaml
<Page.Resources>
<DataTemplate x:Key="PreviewColumnTemplate" x:DataType="models:Column">
<TextBlock>
<Run Text="{x:Bind name}"/>
<Run Text=" ("/>
<Run Text="{x:Bind ColumnValidation.column_label}"/>
<Run Text=") "/>
</TextBlock>
</DataTemplate>
<Style x:Key="previewColumnListViewItem" TargetType="ListViewItem">
</Style>
</Page.Resources>
<ListView
x:Name="previewColumnListView"
ItemsSource="{x:Bind ViewModel.CurrentDrillHole.Collar.Columns, Mode=TwoWay}"
ItemTemplate="{StaticResource PreviewColumnTemplate}"
Height="400"
SelectionMode="Multiple"
SelectionChanged="previewColumnListView_SelectionChanged">
<ListView.Resources>
<Style TargetType="ListViewItem" BasedOn="{StaticResource previewColumnListViewItem}">
<Setter Property="IsSelected" Value="{Binding Selected, Mode=TwoWay}"/>
</Style>
</ListView.Resources>
</ListView>
The ViewModel.CurrentDrillHole.Collar object is of type Table and looks like so:
public class Table : BindableBase
{
public string Name { get; set; }
public TableValidation TableValidation { get; set; }
public List<Column> Columns { get; set; }
public List<Row> Rows { get; set; } = new List<Row>();
}
And the Column object looks like so. It is here I want to bind to the Selected property.
public class Column : BindableBase, INotifyPropertyChanged
{
public string name { get; set; }
public ColumnValidation ColumnValidation { get; set; }
public List<RefEntryValue> LookupValues { get; set; } = null;
private bool _selected = false;
public bool Selected {
get => _selected;
set
{
_selected = value;
OnPropertyChanged();
}
}
}
Any ideas of things I can try would be greatly appreciated. Thanks for the help!
When you set SelectionMode="Multiple", ListViewItem uses the default ListViewItemTemplate whose key is "ListViewItemExpanded".
Its style is as follows:
<Style TargetType="ListViewItem" x:Key="ListViewItemExpanded">
......
<ControlTemplate TargetType="ListViewItem">
<Grid x:Name="ContentBorder"
Control.IsTemplateFocusTarget="True"
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
RenderTransformOrigin="0.5,0.5">
……
<Border x:Name="MultiSelectSquare"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
BorderThickness="2"
Width="20"
Height="20"
Margin="12,0,0,0"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Visibility="Collapsed">
<Border.Clip>
<RectangleGeometry Rect="0,0,20,20">
<RectangleGeometry.Transform>
<TranslateTransform x:Name="MultiSelectClipTransform" />
</RectangleGeometry.Transform>
</RectangleGeometry>
</Border.Clip>
<Border.RenderTransform>
<TranslateTransform x:Name="MultiSelectCheckBoxTransform" />
</Border.RenderTransform>
<FontIcon x:Name="MultiSelectCheck"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Glyph=""
FontSize="16"
Foreground="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
Visibility="Collapsed"
Opacity="0" />
</Border>
<Border x:Name="MultiArrangeOverlayTextBorder"
Opacity="0"
IsHitTestVisible="False"
Margin="12,0,0,0"
MinWidth="20"
Height="20"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
BorderThickness="2"
BorderBrush="{ThemeResource SystemControlBackgroundChromeWhiteBrush}">
<TextBlock x:Name="MultiArrangeOverlayText"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DragItemsCount}"
Style="{ThemeResource CaptionTextBlockStyle}"
IsHitTestVisible="False"
Opacity="0"
VerticalAlignment="Center"
HorizontalAlignment="Center"
AutomationProperties.AccessibilityView="Raw" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Style>
As you can see, there is no CheckBox in its style, it is composed by Border and FontIcon.
If you want to solve this problem, I suggest that you could add CheckBox to DataTemplate. By doing this, we can bind “Selected’ to the “IsChecked” property of the CheckBox.
Please refer to the following code.
<ListView
x:Name="previewColumnListView"
ItemsSource="{x:Bind ViewModel.CurrentDrillHole.Collar.Columns, Mode=TwoWay}"
Height="400"
SelectionChanged="previewColumnListView_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate x:Key="PreviewColumnTemplate" x:DataType="models:Column">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Selected, Mode=TwoWay}"/>
<TextBlock>
<Run Text="{x:Bind name}"/>
<Run Text=" ("/>
<Run Text="{x:Bind ColumnValidation.column_label}"/>
<Run Text=") "/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is how it ended up looking in the end. Does this seem clunky to anyone else? It would be nice if the ListView control made it easier to deal with collections and SelectionMode="Multiple".
SettingsPage.xaml
<ListView
x:Name="previewColumnListView"
ItemsSource="{x:Bind ViewModel.CurrentDrillHole.Collar.Columns, Mode=TwoWay}"
Height="400"
SelectionChanged="previewColumnListView_SelectionChanged"
IsItemClickEnabled="True"
ItemClick="previewColumnListView_ItemClick">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Column">
<StackPanel Orientation="Horizontal">
<CheckBox Click="previewColumnListView_CheckBox_Click" IsChecked="{Binding Selected, Mode=TwoWay}"/>
<TextBlock>
<Run Text="{x:Bind name}"/>
<Run Text=" ("/>
<Run Text="{x:Bind ColumnValidation.column_label}"/>
<Run Text=") "/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
SettingsPage.xaml.cs
private async void previewColumnListView_CheckBox_Click(object sender, RoutedEventArgs e)
{
// update the list of selected columns
Settings.CollarPreviewFields = ViewModel.CurrentDrillHole.Collar.Columns.Where(x => x.Selected).Select(x => x.name).ToList();
await App.SaveSettings();
}
private void previewColumnListView_ItemClick(object sender, ItemClickEventArgs e)
{
Column selectedColumn = (Column)e.ClickedItem;
selectedColumn.Selected = !selectedColumn.Selected;
// trigger checkbox click event. will update the list and save.
previewColumnListView_CheckBox_Click(null, null);
}

UWP Exception when binding to ComboBox

I am getting this exception:
An unhandled win32 exception occurred in AppName.exe
This occurs only when I Bind to a ComboBox
Here's my XAML:
<ContentDialog x:Name="BrowseBySourceDialog"
Grid.Column="1"
PrimaryButtonText="Accept" IsPrimaryButtonEnabled="False"
Opened="BrowseBySourceDialog_Opened">
<StackPanel Background="White">
<Border Background="DarkGreen" MinHeight="40"
MinWidth="300">
<TextBlock Text="Browse: By Source"
VerticalAlignment="Center"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center" />
</Border>
<StackPanel>
<ComboBox x:Name="BrowseBySourceComboBox"
PlaceholderText="Select Source"
Height="40"
Width="300"
ItemsSource="{x:Bind BrowseBySourceList, Mode=OneWay}"
DisplayMemberPath="Source">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:FeaturedResponseItem">
<TextBlock Text="{x:Bind key}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</StackPanel>
</ContentDialog>
This exception only occurs when the following lines are present:
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:FeaturedResponseItem">
<TextBlock Text="{x:Bind key}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
If the remove the above lines, the combobox surely remains empty but the exception doesn't occur. Is the binding wrong?
Source:
ObservableCollection<FeaturedResponseItem> BrowseBySourceList { get; set; } = new ObservableCollection<FeaturedResponseItem>();
Model:
public class FeaturedResponseItem
{
public string key { get; set; }
public string icon { get; set; }
public bool accessible { get; set; }
}
You can delete DisplayMemberPath="Source" or simply just remove the ItemTemplate all together and change DisplayMemberPath="Source" to DisplayMemberPath="Key".

WinRT Binding data of ViewMode inside a DataTemplate

I wanted to bind data inside a DataTemplate that is stored in ViewModel. I've tried several ways but did not succeed and the solutions for WPF doesn't seems to work on WinRT like AncestorType Property of RelativeSource.
<Page.DataContext>
<local:ViewModel x:Name="ViewModel" />
</Page.DataContext>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{x:Bind ViewModel.names}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:mydatatype">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<!--Here I want a TextBlock to show the number-->
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
Here is the ViewModel
public class ViewModel
{
public int Number = 42;
public List<mydatatype> names = new List<mydatatype>();
public ViewModel()
{
names.Add(new mydatatype("name1"));
names.Add(new mydatatype("name2"));
}
}
public class mydatatype
{
public string Name { get; set; }
public mydatatype(string name)
{
this.Name = name;
}
}
You can access the DataTemplate of other objects by giving them a name and then referencing this. Using this technique you should be able to access its DataContext to bind to the viewmodel directly, even from within a DataTemplate
<Page x:Name="PageRoot">
<Page.DataContext>
<local:ViewModel x:Name="ViewModel" />
</Page.DataContext>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" x:Name="MainPanel">
<ListView ItemsSource="{x:Bind ViewModel.names}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:mydatatype">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding DataContext.Name, ElementName=PageRoot}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Page>

XAML Gridview to add an item directly

I successfully coded an XAML Gridview to show list of items.
However, I want to add an [+(ADD ITEM)] button at the end of the Gridview.
The ADD button has should have a custom template (at least a default button) which is different from the content item.
My XAML source is below:
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemsGridView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.RowSpan="2"
Padding="116,136,116,46"
ItemsSource="{Binding Source={StaticResource DataSource}}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}">
<StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Subject}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource BaseTextBlockStyle}" Height="60" Margin="15,0,15,0" FontWeight="SemiBold"/>
<TextBlock Text="{Binding TargetDate}" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource BaseTextBlockStyle}" TextWrapping="NoWrap" Margin="15,0,15,10" FontSize="12"/>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<!--
Something like that..
<Button Content="+" x:Name="btnAdd" />
-->
</GridView>
And, how can I add a ADD button(grid item) to XAML? thanks
You can achieve that by using a DataTemplateSelector, basically what you need to do is :
define another class that will represent the GridView "addItem"
public class GridItem
{
public String Subject { get; set; }
public String TargetDate { get; set; }
}
public class AddGridItem : GridItem
{
public bool IsGridItem { get; set; }
}
Make sure that your GridView's ItemSource collection has always an AddGridItem in it
private ObservableCollection<GridItem> _gridItems =new ObservableCollection<GridItem>()
{
new GridItem()
{
Subject = "Subject1",
TargetDate = "TargetDate"
},new GridItem()
{
Subject = "Subject2",
TargetDate = "TargetDate"
},new GridItem()
{
Subject = "Subject3",
TargetDate = "TargetDate"
},new AddGridItem()
{
IsGridItem = true
}
};
public ObservableCollection<GridItem> GridItems
{
get
{
return _gridItems;
}
set
{
if (_gridItems == value)
{
return;
}
_gridItems = value;
}
}
Create a DataTemplateSelector class that will return the appropriate DataTemplate based on the Item type
public class MyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate RegularTemplate { get; set; }
public DataTemplate AddTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item,
DependencyObject container)
{
if (item is AddGridItem)
return AddTemplate;
if (item is GridItem)
return RegularTemplate;
return base.SelectTemplateCore(item, container);
}
}
Define your dataTempaltes and a DataTemplateSelector as staticresources to use them in your GridView
<Page.Resources>
<DataTemplate x:Key="RegularTemplate">
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border BorderThickness="3" BorderBrush="White">
<StackPanel VerticalAlignment="Bottom" Background="LightSkyBlue">
<TextBlock Text="{Binding Subject}" Style="{StaticResource BaseTextBlockStyle}" Height="60" Margin="15,0,15,0" FontWeight="SemiBold"/>
<TextBlock Text="{Binding TargetDate}" Style="{StaticResource BaseTextBlockStyle}" TextWrapping="NoWrap" Margin="15,0,15,10" FontSize="12"/>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
<DataTemplate x:Key="AddItemTemplate">
<Border BorderThickness="3" BorderBrush="White" Background="DodgerBlue">
<FontIcon Glyph="" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/>
</Border>
</DataTemplate>
<local:MyDataTemplateSelector x:Key="MyDataTemplateSelector"
RegularTemplate="{StaticResource RegularTemplate}"
AddTemplate="{StaticResource AddItemTemplate}">
</local:MyDataTemplateSelector>
</Page.Resources>
<Grid>
<GridView ItemsSource="{Binding GridItems}" ItemTemplateSelector="{StaticResource MyDataTemplateSelector}">
</GridView>
</Grid>

validate a cell based on another cell value in datagrid in silverlight

PFB the code for datagrid in our silverlight app,i need to validate the column AttributeValue in each row based on other column value DatatypeName, for example the DatatypeNamecolumn value for a particular row is int the AttributeValue column in the same row should allow user only int ,if user enters other than int the cell should throw validation exception.Please help
<sdk:DataGrid Margin="0,0,0,50" Grid.Row="1" Grid.Column="0" RowStyle="{StaticResource DataGridRowStyle1}" Style="{StaticResource DataGridStyle1}" IsReadOnly="True" Foreground="{StaticResource GrayBrush}" HorizontalScrollBarVisibility="Hidden" Name="dgKpiAttributes" MinHeight="5" VerticalAlignment="Stretch" FontSize="13.333" FontFamily="Segoe UI" AutoGenerateColumns="False" GridLinesVisibility="None" >
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header=" " >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chkSelect"
VerticalAlignment="Center" IsChecked="False" HorizontalAlignment="Center" HorizontalContentAlignment="Center"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="AttributeName" SortMemberPath="AttributeName" Width="50*" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="txtAttributeName" TextWrapping="Wrap" Padding="4" Text="{Binding AttributeName}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="AttributeValue" SortMemberPath="AttributeValue" Width="80*" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center">
<TextBox x:Name="AttributeValue" Margin="0,0,10,0" HorizontalAlignment="Stretch" Text="{Binding AttributeValue}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="DataType" SortMemberPath="DataTypeName" Width="50*">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center">
<TextBox x:Name="DatatypeName" HorizontalAlignment="Stretch" TextWrapping="Wrap" IsEnabled="False" Text="{Binding DataTypeName}" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
Well, from your code I can see your class is like this (correct me if I'm mistaken):
class MyClass
{
public string AttributeName {get;set;}
public string AttributeValue {get;set;}
public string DatatypeName {get;set;}
}
In silverligth, I suppose there is a way to check another cells in the same row in a datagrid, but since you are working with bindings, you do not need that, you can work directly in your data object:
class MyClass
{
public string AttributeName {get;set;}
public string DatatypeName {get;set;}
private string _AttributeValue;
public string AttributeValue {
get{
return _AttributeValue;
}
set{
if (validate(DatatypeName,value)){
//Do something if validation is a success
_AttributeValue = value;
}
else{
//Do something if validation fails
}
}
}
bool validate(string typename,string value){
//do your validation, return true or false
return true
}
}
This way you do not need to concern yourself with traversing the UI, only with the data.