Silverlight TreeViewItem, Binding to IsSelected, how to? - silverlight-4.0

In reading a post about TreeView and binding to a view model (http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx), it seems that binding a TreeViewItem IsSelected property is possible. However, I have the following code which always fails on Initialize() because it's trying to set a read-only property?
<sdk:TreeView Grid.Column="0" Grid.Row="2" Style="{StaticResource TreeViewStyle}"
ItemsSource="{Binding tvData}" >
<sdk:TreeView.ItemContainerStyle>
<Style TargetType="sdk:TreeViewItem">
<Setter Property="IsEnabled" Value="True" />
<Setter Property="IsExpanded" Value="True" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</sdk:TreeView.ItemContainerStyle>
<sdk:TreeView.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ItemName}" FontWeight="{Binding ItemFontWeight}"/>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>

You can't assign a binding via a Setter in a Style. Effectively what you are doing there is attempting to set a binding on the Setter.Value property. Xaml doesn't infer that you mean to set a binding on the target property. In turn the Setter just assumes you are trying to set a value directly to IsSelected which it knows is read only hence the error.

I can recommend this technique for getting around the problem:
http://blogs.msdn.com/b/delay/archive/2009/05/07/one-more-platform-difference-more-or-less-tamed-settervaluebindinghelper-makes-silverlight-setters-better.aspx
EDIT:
I should mention that I have not tried the technique for this exact scenario (binding the IsSelected property of a TreeViewItem), but I have used it on numerous other occasions, and so far it has worked flawlessly.

Related

Unable to Bind ListView.SelectedItems.Count to Button.IsEnabled

I have a Button that I want to bind to the listview's selectedItem count. I cannot find where my error is. The button state is always enabled regardless of testListView.SelectedItems.Count.
Do I need a converter of some sort? If the Count is zero, it should implicitly convert that to a false no ?
<ListView x:Name="testListView" SelectionMode="Multiple" BorderThickness="1">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button x:Name="Button" Content="TestButton" IsEnabled="False" IsEnabled="{Binding ElementName=testListView, Path=SelectedItems.Count}"/>
Since the SelectedItems collection's Count property is of type int, and the IsEnabled property expects a bool input, and no implicit conversion of int to bool exists in C#, you'll need a converter or a data trigger.
A simple IValueConverter should do the trick, just use something like
return ((int)value) > 0;
as content of the Convert function!
Update using a DataTrigger via a Style; something like this should work:
<Button x:Name="Button" Content="TestButton">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="true" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=testListView, Path=SelectedItems.Count}" Value="0">
<Setter Property="IsEnabled" Value="false" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

Cannot set ListViewItem.IsSelected using ListView.ItemContainerStyle in WinRT

Trying to set the IsSelected Property for all items to be TRUE on a Multiple Select Mode ListView. I think I have the syntax correct. Any guesses as to what is wrong?
<ListView x:Name="myListView" SelectionMode="Multiple" BorderThickness="1"
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Thumbnail}"/>
<TextBlock Text="{Binding dataSource.Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="True" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
Turns out this is not possible in WINRT
Workaround found # http://pmichaels.net/2014/09/18/binding-isselected-method-in-the-listview-control-in-winrt/
I have answered in comment for your another question, but still.
Unfortunately, bindings are not supported on Setters in WinRT. I think Silverlight only got them in version 5. For workarounds you basically could define an attached dependency property that sets up the binding for you. You can have a look here: here
Hope this helps!

ListBox and ApplicationBar: last element padding

I have a ListBox and ApplicationBar with Opacity=.5. I want that ListBox items are under the ApplicationBar.
Like figure:
But when I scrolled to end of list then last element of ListBox is under the ApplicationBar.
I want that last element is over ApplicationBar.
Can I add padding for a last element of the ListBox (LongListSelector)? How can solved this issue?
UPDATE
<ListBox Name="MyListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<i:Interaction.Triggers>
<ec:DataTrigger Binding="{Binding RelativeSource=
{RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}"
Value="True">
<ec:ChangePropertyAction PropertyName="Padding" Value="0,0,0,72"/>
</ec:DataTrigger>
</i:Interaction.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="Red"
Width="400"
Height="120"
Margin="15">
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
UPDATE 2
My problem can be easily solved by using LongListSelector. Just add empty ListFooterTemplate with Height = ApplicationBar height.
You can use converter to check if it's last item in listbox and in case yes, set padding to desired value via DataTrigger.
Check my answer over here for converter code. Just for sake of completeness of this answer i will post that converter code here:
public class IsLastItemInContainerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item)
== ic.Items.Count - 1;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and use it like this:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource=
{RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}"
Value="True">
<Setter Property="Padding" Value="5"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
edit: Didn't see the update to the original question. The below remains for additional detail.
This solution is for Windows Phone 8 only (although you could use the LongListSelector from the Windows Phone Toolkit if you are targeting 7.1/5).
I'd replace the ListBox with the LongListSelector from the SDK
<Grid>
<controls:LongListSelector ItemTemplate="{StaticResource Item}" ListFooterTemplate="{StaticResource Footer}" />
</Grid>
and for the templates add
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="Item">
<StackPanel Background="Red"
Width="400"
Height="120"
Margin="15">
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="Footer">
<Border Height="72" />
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Maybe simplest solution is to customize ItemsPanel property on ListBox:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Margin="0,0,0,150"/> <!-- set margin to show some 'blank' space after last item -->
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
...
</ListBox>
But be aware that by default ListBox uses VirtualizedStackPanel as ItemsPanel. If you change it to StackPanel, it may bring some performance penalty. This is solution is suitable for lists with few items.

How to reuse Xaml code templates?

Say i have this XAML :
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
I'd like re use it across multiple places.
For example as a DataTemplate for a ItemsControl but also as The basis for something like a buttons content.
How would i go about doing this?
I'm thinking something like an ASP.NET Partial view.
I don't want to use a usercontrol as i don't require any code behind.
I managed to get it to work in a way using a style:
<Style x:Key="myStyle" TargetType="Control">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It insisted on me using a TargetType otherwise it complained about setting the template.
I can now use this on any control.
If i want to then use this essentially as a datatemplate, i can just set the style of the placeholder item within the datatemplate (probably a ContentControl) to use this.
Create a StylesResourceDictionary.xaml and create a staticresource in your App.Xaml. At runtime, the styles will get binded and then you can reference anything from the dictionary anywhere in your app, across usercontrols or datatemplates etc.

Silverlight Listbox update style at runtime

I have a listbox control added to my layout as show in the below code snippet.
<ListBox x:Name="lstFilters" ItemsSource="{Binding CustomerCollection, Source={StaticResource VMCustomers}}" ScrollViewer.VerticalScrollBarVisibility="Disabled" Height="200" Margin="12,20,235,80">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<HyperlinkButton Content="{Binding Name}" Style="{StaticResource styleFont}"></HyperlinkButton>
<TextBlock x:Name="txtFilterCount" Text="{Binding ContactNumber, Mode=TwoWay}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Style x:Key="styleFont" TargetType="HyperlinkButton">
<Setter Property="FontFamily" Value="Verdana"></Setter>
</Style>
I have written a style that sets the font family to HyperlinkButton control.
Now i want to set this fontfamily from code behind because i am getting the value at runtime. so how to change it and one more thing i want to do this at the constructor or page load event i.e. i want to set this only once and it should apply for all the items i.e if there are 100 items then it should get applied to all the 100 items. so it makes it faster instead of always binding it any event.
The easiest way to do this is to bind the style to a property of the UserControl using the following XAML:
<Style x:Key="styleFont" TargetType="HyperlinkButton">
<Setter Property="FontFamily"
Value="{Binding DataContext.ListFont,
RelativeSource={RelativeSource AncestorType=UserControl}}">
</Setter>
</Style>
Then you just need to update the property and the style will reflect the new Font for all the list items.
Update:
This answer is only valid for Silverlight 5.