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

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>

Related

Datatrigger with DynamicResource works only on last item in ItemsControl

My DashBoardSimpleCountObject has 2 values: MyName and MyValue.
I use an ObservableCollection<DashboardSimpleCountObject> called MyData.
I want to show a picture, as long as MyValue is null.
However, the picture ("loading") is only shown at the last item of my ObservableCollection (no matter, how many items are in there). As soon as a MyValue is set (with anything other than null), it is automatically updated and shown correctly - that works fine at all items.
<ItemsControl x:Name="_control" ItemsSource="{Binding MyData}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="25">
<Label FontSize="14" Content="{Binding MyName}" />
<Label Margin="0,25" HorizontalContentAlignment="Right" FontSize="29" FontWeight="ExtraBold" Foreground="{Binding MyColor}">
<Label.Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Content" Value="{Binding MyValue}" />
<Style.Triggers>
<DataTrigger Binding="{Binding MyValue}" Value="{x:Null}">
<Setter Property="Content">
<Setter.Value>
<Image Width="32" Height="32" Source="{DynamicResource loading}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
What am I doing wrong?
Thank you very much in advance! :)
It seems, the nature of DynamicResource causes this issue.
Simply changing DynamicResource to StaticResource did the trick.
So, the DataTrigger worked just fine from the beginning. The image simply did only show up once due to being loaded as a DynamicResource.

LayoutAnchorable Title font

For the XAML below I'm using AvalonDock 2.0.2. I'm wanting to set the font of the Title property of the LayoutAnchorable
<xcad:DockingManager Name="TabItemDockingManager"
AllowMixedOrientation="True"
BorderBrush="Black"
BorderThickness="0" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
AnchorablesSource="{Binding Anchorables, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" viewModels:AvalonDockLayoutSerializer.LoadLayoutCommand="{Binding ADLayout.LoadLayoutCommand}" viewModels:AvalonDockLayoutSerializer.SaveLayoutCommand="{Binding ADLayout.SaveLayoutCommand}">
<xcad:DockingManager.LayoutUpdateStrategy>
<pane:LayoutInitializer/>
</xcad:DockingManager.LayoutUpdateStrategy>
<xcad:DockingManager.LayoutItemTemplateSelector>
<pane:PanesTemplateSelector>
<pane:PanesTemplateSelector.MyViewTemplate>
<DataTemplate>
...
</DataTemplate>
</pane:PanesTemplateSelector.MyViewTemplate>
</pane:PanesTemplateSelector>
</xcad:DockingManager.LayoutItemTemplateSelector>
<xcad:DockingManager.LayoutItemContainerStyleSelector>
<pane:PanesStyleSelector>
<pane:PanesStyleSelector.ToolStyle>
<Style TargetType="{x:Type xcad:LayoutAnchorableItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
</Style>
</pane:PanesStyleSelector.ToolStyle>
</pane:PanesStyleSelector>
</xcad:DockingManager.LayoutItemContainerStyleSelector>
<xcad:LayoutRoot x:Name="_LayoutRoot">
<xcad:LayoutPanel Orientation="Vertical">
<xcad:LayoutAnchorablePane Name="AnchorablesPane" DockHeight="150">
</xcad:LayoutAnchorablePane>
</xcad:LayoutPanel>
</xcad:LayoutRoot>
</xcad:DockingManager>
I can set the Title text (which is done via reading/loading the layout), however I don't see a Font/FontFamily property I can set
Does anyone know how this can be done ?
Thanks to Attila (apols that I cannot mark his answer as I don't have enough points)
AvalonDock 2.2 - Full width TitleTemplate (fill parent container)
AvalonDock is a fantastic library - that said implementing it with MVVM is a challenge but the below seems to work well
<xcad:DockingManager.Resources>
<DataTemplate x:Key="DockingWindowTitleDataTemplate" DataType="{x:Type xcad:LayoutContent}">
<Label>
<TextBlock Text="{Binding Path=Title}" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="14" />
</Label>
</DataTemplate>
</xcad:DockingManager.Resources>
<xcad:DockingManager.AnchorableTitleTemplate>
<StaticResource ResourceKey="DockingWindowTitleDataTemplate" />
</xcad:DockingManager.AnchorableTitleTemplate>

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.

Make XAML Controls "go on top" of other controls when mouse over

I have three buttons, one on top of the other in XAML like so:
<Grid>
<Button
Width="50"
Height="50"
Background="Red"/>
<Button
Margin="10"
Width="50"
Height="50"
Background="Blue"/>
<Button
Margin="20"
Width="50"
Height="50"
Background="Green"/>
</Grid>
How do I change their Z-Order when the mouse is over them?
Put this to the Grid.Resources
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Panel.ZIndex" Value="99999"/>
</Trigger>
</Style.Triggers>
</Style>
when IsMouseOver is false the button instances gets back its original zindex value

Styling ListBox with Static Content

I have a set of static content that I want in a ListBox control.
<ListBox>
<ListBox.Items>
<ListBoxItem>
<Image />
<TextBlock Text="One" />
</ListBoxItem>
<ListBoxItem>
<Image />
<TextBlock Text="Two" />
</ListBoxItem>
<ListBoxItem>
<Image />
<TextBlock Text="Three" />
</ListBoxItem>
</ListBox.Items>
</ListBox>
How do I go about styling this? I know I can style each ListBoxItem individually, and I know how to style when data bound, but how do I style the a listbox item template when using static content like this?
You can define the items as low-level objects and use data-templating, which may not be the same as styles but properties are only set once as well:
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ListBox.Items>
<sys:String>one</sys:String>
<sys:String>two</sys:String>
<sys:String>three</sys:String>
</ListBox.Items>
<ListBox.ItemTemplate>
<DataTemplate>
<!-- "Style" this at will -->
<StackPanel>
<Image />
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
(To style the wrapping ListBoxItems you can try using an implicit style defined in the ListBox.Resources)
The following only works in WPF
Add a style to the resources of the ListBox and only set the TargetType and not the x:Key, it will be applied automatically.
You can even nest this automatic application using Resources, e.g.:
<ListBox>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<Style TargetType="{x:Type Image}">
<Setter Property="Width" Value="100"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Blue"/>
</Style>
</Style.Resources>
</Style>
</ListBox.Resources>
<!-- Items here -->
</ListBox>