Items collection must be empty before using ItemsSource in Silverlight - silverlight

Inside custom control I'm trying to bind my ItemsControl.ItemsSource and get error. Here is how template looks:
<Style TargetType="controls:IdattFilterBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:IdattFilterBox">
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto">
<ItemsControl x:Name="PART_ItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Caption}" />
<ComboBox Grid.Column="1">
<ComboBoxItem Content="Contains" />
<ComboBoxItem Content="Begins with" />
<ComboBoxItem Content="Ends with" />
</ComboBox>
<TextBox Grid.Column="2" Text="{Binding FieldFilter1, Mode=TwoWay}" />
<TextBox Grid.Column="3" Text="{Binding FieldFilter2, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<Border Grid.ColumnSpan="2" x:Name="ValidationErrorElement" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" Visibility="Collapsed">
<ToolTipService.ToolTip>
<ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource ValidationToolTipTemplate}">
<ToolTip.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>true</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
</ToolTipService.ToolTip>
<Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
<Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>
<Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>
</Grid>
</Border>
</ItemsControl>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In code I' trying to set this PART's ItemSource:
this.WrapperItemsControl.ItemsSource = filterData;
On this line I get error(error message in subject). Why can't I set ItemsSource and what this error means? I want controls in DataTemplate to bind to objects that stored in filterData.
EDIT:
PART_ItemsControl is what my WrapperItemsControl
this.WrapperItemsControl = GetTemplateChild(PartItemsControl) as ItemsControl;
EDIT2:
Screenshot showing that there is one item (Border?) Where does it come from?!
EDIT3
DOH! I placed validation border in a wrong spot

You can't use ItemsSource if you manually add items to your ItemsControl. For example, you would get an error if you tried this:
<ItemsControl ItemsSource="{Binding MyItems}">
<ListBoxItem>Item1</ListBoxItem>
<ListBoxItem>Item2</ListBoxItem>
</ItemsControl>
You may think you're not doing that, but you actually are. You're adding a single item to your ItemsControl, and that item is of type DataTemplate. Look:
<ItemsControl ...>
<DataTemplate ... />
That syntax means "create a DataTemplate and add it to the ItemsControl's Items property". (Items is the default property for ItemsControl, so any elements you nest under ItemsControl, if you don't otherwise specify, get added to Items.)
I think you intended to assign that DataTemplate to the ItemsControl's ItemTemplate property, rather than adding it to Items. Try this instead:
<ItemsControl ...>
<ItemsControl.ItemTemplate>
<DataTemplate ... />
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

WPF - How to use Badge in Mahapps HamburgerMenuItem

Quick question for who known WPF:
How to add a badge in a Mahapps HamburgerMenuItem?
I use this template:
<DataTemplate x:Key="MenuItemTemplate" DataType="{x:Type Controls:HamburgerMenuIconItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle Width="20" Height="20" HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle.Fill>
<VisualBrush Stretch="Fill" Visual="{Binding Icon}" />
</Rectangle.Fill>
</Rectangle>
</ContentControl>
<TextBlock Grid.Column="1" VerticalAlignment="Center" FontSize="16" Foreground="White" Text="{Binding Label}" />
</Grid>
</DataTemplate>
And here is my Hamburger Items:
<Controls:HamburgerMenuItemCollection>
<Controls:HamburgerMenuIconItem Icon="{StaticResource appbar_home_variant}" Label="Home">
<Controls:HamburgerMenuIconItem.Tag>
<Grid Name="HomeView"></Grid>
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{StaticResource appbar_people_status}" Label="Private" >
<Controls:HamburgerMenuIconItem.Tag>
<Grid Name="PrivateView"></Grid>
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{StaticResource appbar_page_onenote}" Label="Notes">
<Controls:HamburgerMenuIconItem.Tag>
<Grid Name="NotesView"></Grid>
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{StaticResource appbar_cog}" Label="Settings">
<Controls:HamburgerMenuIconItem.Tag>
<Grid Name="SettingsView"></Grid>
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
</Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.ItemsSource>
Here what I am looking for:
HamburgerMenu Badge
Regards,
As I found here
You can wrap them arround your Icon.
<Controls:Badged Badge="{Binding Path=BadgeValue}" BadgePlacementMode="BottomRight">
<!-- Control to wrap goes here -->
<Button>
<iconPacks:PackIconFontAwesome Kind="CommentOutline"/>
</Button>
</Controls:Badged>
In your example it would be:
<Controls:Badged Badge="{Binding Path=BadgeValue}">
<Controls:HamburgerMenuIconItem Icon="{StaticResource appbar_home_variant}" Label="Home">
<Controls:HamburgerMenuIconItem.Tag>
<Grid Name="HomeView"></Grid>
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
</Controls:Badged>
it is possible. But it will get cut and does not look very good IMO
Example closed:
Example opened:
How to get it?:
Just wrap your Icon in the DataTemplate with a Badge:
<DataTemplate x:Key="HamburgerMenuItem" DataType="{x:Type Controls:HamburgerMenuGlyphItem}">
<DockPanel Height="48" LastChildFill="True">
<Controls:Badged x:Name="IconPart"
Width="48"
Badge="?"
BadgeBackground="Red"
DockPanel.Dock="Left">
<Image Margin="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="{Binding Glyph}"
Stretch="UniformToFill" />
</Controls:Badged>
<TextBlock x:Name="TextPart"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Label}" />
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:HamburgerMenu}}, Path=PanePlacement}" Value="Right">
<Setter TargetName="IconPart" Property="DockPanel.Dock" Value="Right" />
<Setter TargetName="TextPart" Property="Margin" Value="8,0,0,0" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
You can modify this to your needs.
UPDATE: Here are additional information from the maintainer of MahApps: https://github.com/MahApps/MahApps.Metro/issues/3800#issuecomment-631103384
I hope this helps and happy coding
Tim

Focusing Listbox item when a control is clicked inside datatemplate

I have a button and on click of button a popup opens up which has a listbox. The items inside the listbox is templated and the template contains a date picker and 2 textboxes to enter date, the hour and minute.
The issue I'm facing with this is this - what ever I do on my datepicker or textboxes, the listbox item does't get focus unless I somehow explicitly click on the spaces btw the controls. Question is-how do i set the listbox item to be the selected item when any of the controls inside the datatemplate is clicked/focused? Please note that I follow MVVM.
Code:
ListBox:
<ListBox x:Name="AsOfList" SelectedItem="{Binding SelectedAsOfDate}" ItemsSource="{Binding Path=AsOfDates}"/>
DataTemplate:
<DataTemplate DataType="{x:Type Domain:UserDefinedDate}">
<DatePicker DockPanel.Dock="Left" Name="AsOfDate" Width="115" SelectedDate="{Binding SelectedDate,
UpdateSourceTrigger=PropertyChanged}" SelectedDateFormat="Short" FirstDayOfWeek="Monday" />
</DataTemplate>
Button:
<Button Grid.Row="1" Grid.Column="1" Height="25" HorizontalAlignment="Center" VerticalAlignment="Center" Name="SelectedDate" Click="SelectedDate_Click"
ToolTip="{Binding Path=AsOfDateViewModel.ToolTip}">
<Button.Content>
<DockPanel>
<TextBlock Text="{Binding Path=AsOfDateViewModel.DisplayText}" />
<Image Height="10" Width="10" Source="Down.png" />
</DockPanel>
</Button.Content>
</Button>
Popup:
<Popup x:Name="DateSelectorPopUp" PlacementTarget="{Binding ElementName=SelectedDate}" StaysOpen="False"
IsOpen="{Binding Path=AsOfDateViewModel.IsOpen}" >
<Views:AsOfDateSelector Width="Auto" DataContext="{Binding Path=AsOfDateViewModel}"/>
</Popup>
You can start BooleanAnimationUsingKeyFrames animation to set IsSelected when GotKeyboardFocus is triggered on ListBoxItem:
<ListBox x:Name="AsOfList" SelectedItem="{Binding SelectedAsOfDate}" ItemsSource="{Binding Path=AsOfDates}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<EventTrigger RoutedEvent="GotKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
</ListBox.ItemTemplate>
</ListBox>

Animate Insertions to ItemsControl

I'm finding WPF inscrutable at times. Given the following XAML how would one add triggers to animate (slide down, fade in) new items added to the ObservableCollection Timeline. I've seen various examples for list boxes but nothing for items control.
<Grid>
<ScrollViewer>
<ItemsControl Name="TimelineItem"
ItemsSource="{Binding Timeline}"
Style="{StaticResource TimelineStyle}"
ItemContainerStyle="{StaticResource TweetItemStyle}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid VerticalAlignment="Top"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Style="{StaticResource TweetImageColumnStyle}" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle Grid.Column="0"
Style="{StaticResource TweetImageStyle}">
<Rectangle.Fill>
<ImageBrush ImageSource="{Binding ProfileImageUrl}" />
</Rectangle.Fill>
</Rectangle>
<StackPanel Grid.Column="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Style="{StaticResource TweetNameStyle}"
Text="{Binding Name}" />
<TextBlock Grid.Column="1"
Style="{StaticResource TweetTimeStyle}"
Text="{Binding TimeAgo}" />
</Grid>
<Controls:TextBlockMarkup Grid.Row="1"
Grid.Column="1"
Markup="{Binding MarkupText}"
Style="{StaticResource TweetStyle}" />
</StackPanel>
<Separator Grid.Row="2"
Grid.ColumnSpan="2"
Style="{StaticResource TweetSeparatorTop}" />
<Separator Grid.Row="3"
Grid.ColumnSpan="2"
Style="{StaticResource TweetSeparatorBottom}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
It's been a while since I've animated WPF, but this should work by setting a DataTrigger in the DataTemplate of the ItemsControl for the Loaded Event.
A couple of notes:
Add the following xaml to the DataTemplate of the ItemsControl
Name the <Grid> inside the DataTemplate: "MyGrid"
Add a RenderTransformOriginproperty to the MyGrid to set the Y origin at the top:
<Grid x:Name="MyGrid" RenderTransformOrigin="0.5,0">
Be sure to include the Grid.RenderTransform attached property to your grid (see sample below)
Xaml
<DataTemplate.Resources>
<Storyboard x:Key="ItemAnimation" AutoReverse="False">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyGrid" Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyGrid" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</DataTemplate.Resources>
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource ItemAnimation}" />
</EventTrigger>
</DataTemplate.Triggers>
Add the RenderTransform groups to your Grid
<!-- Include in the Grid -->
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
</TransformGroup>
</Grid.RenderTransform>
This should get you close enough so that you can customize it yourself. FWIW: I used Blend to build out the animation by editing the style of the ItemTemplate of the Timeline object.
One last note: The animation will occur when the window loads the ItemsControl for the first time, for each item in the original collection. And will occur for an individual item when it is added to the collection. This behavior is a bit wonky, so you could remove the explicit binding of the trigger in the xaml and bind the trigger in the code-behind after the ItemsControl or Window loads.
EDIT
I've updated the example so that it should work with your XAML now.
Added another animation to slide (sort of) the new item. Actually, it's growing from a size of 0% to 100%, starting from the top of the Y axis.
Revised note #3 from above to include a RenderTransformOrigin property.
Added note #4 to include the Grid.RenderTransform attached property.

Close popup from child button's press?

I have a Popup that contains a "close" button. The popup is opened by a toggle button (its IsOpen property is bound to a ToggleButton as provided by this answer). How can I close the popup when the button is pressed? This is my XAML:
<Canvas x:Name="LayoutRoot">
<ToggleButton x:Name="ToggleButton"
Style="{DynamicResource ToggleButtonStyle}" Height="51" Canvas.Left="2.999" Width="50.333" IsHitTestVisible="{Binding ElementName=Popup, Path=IsOpen, Mode=OneWay, Converter={StaticResource BoolInverter}}"/>
<Popup x:Name="Popup" IsOpen="{Binding IsChecked, ElementName=ToggleButton}" StaysOpen="False" AllowsTransparency="True">
<Canvas Height="550" Width="550">
<Grid Height="500" Width="500" Canvas.Left="25" Canvas.Top="25" d:LayoutOverrides="Width, Height, Margin">
<Grid.Effect>
<DropShadowEffect BlurRadius="15" ShadowDepth="0"/>
</Grid.Effect>
<Grid.RowDefinitions>
<RowDefinition Height="0.132*"/>
<RowDefinition Height="0.868*"/>
</Grid.RowDefinitions>
<Rectangle x:Name="Background" Fill="#FFF4F4F5" Margin="0" Stroke="Black" RadiusX="6" RadiusY="6" Grid.RowSpan="2"/>
<Border x:Name="TitleBar" BorderThickness="1" Height="70" VerticalAlignment="Top" Margin="0,0.5,0,0" CornerRadius="5">
<DockPanel>
<TextBlock TextWrapping="Wrap" Text="FOOBAR POPUP TITLE" FontSize="24" FontFamily="Arial Narrow" Margin="17,0,0,0" d:LayoutOverrides="Height" VerticalAlignment="Center" FontWeight="Bold"/>
<Button x:Name="CloseButton" Content="Button" VerticalAlignment="Center" DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="0,0,13,0" Style="{DynamicResource CloseButtonStyle}"/>
</DockPanel>
</Border>
<Border BorderThickness="1" Height="413" Grid.Row="1" Background="#FF2F2F2F" Margin="12">
<Rectangle Fill="#FFF4F4F5" RadiusY="6" RadiusX="6" Stroke="Black" Margin="12"/>
</Border>
</Grid>
</Canvas>
</Popup>
</Canvas>
A better approach than code behind is to use an event trigger on the button click event:
<Button>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked" Storyboard.TargetName="ToggleButton">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Disclaimer: I haven't run this code through VS so it might have a typo or 2
Other answers didn't work for me, because I was using a DataTemplate for the buttons inside the popup. After lot's of searching I found that I should use Storyboard.Target instead of Storyboard.TargetName. Otherwise the x:Name was not found and there was some namespace exception.
<ToggleButton x:Name="MyToggleButtonName" Content="{Binding MyToggleButtonString}"/>
And later inside the Popup that has a ListBox which is populated from some ItemsSource:
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name, Mode=OneWay}"
Command="{StaticResource MyCommandThatTakesAParameter}"
CommandParameter="{Binding Name}">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked" Storyboard.Target="{Binding ElementName=MyToggleButtonName}">
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
This way it is possible to get a somewhat working ComboBox which can execute commands with the buttons inside it. (A normal ComboBox can't launch commands for some odd reason.)
One way of doing it is to add event handler for your CloseButton:
<Button x:Name="CloseButton" Click="OnButtonClick" Content="Button" VerticalAlignment="Center" DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="0,0,13,0" Style="{DynamicResource CloseButtonStyle}"/>
And in OnButtonClick event handler set state of your
TuggleButton.IsChecked = false;
I have't tested code in VS, so there might be some typos

How to show a divider between items in a ListBox?

I am using a ListBox control in a Windows Phone 7 application, and I would like to show a divider/line between the list rows.
I have not been able to find any information about this, although many (not wp7) ListBox examples seem to have a divider.
Got inspired by NestorArturo and found out about the Border control.
It is very easy to wrap your ItemTemplate content in a Border control and specify the BorderThickness and BorderBrush. I went this way, because it doesn't require changes to my Grid in the ItemTemplate.
The Border control is described here: http://www.silverlightshow.net/items/Using-the-Border-control-in-Silverlight-2-Beta-1-.aspx.
Below you can see how I use it:
<ListBox Background="White" ItemsSource="{Binding Mode=OneWay, Path=MyPath}" Name="listName" SelectionChanged="listName_SelectionChanged">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
here --> <Border BorderThickness="0,10,0,10" BorderBrush="Black">
<Grid Width="auto" HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="48" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" FontSize="36" FontWeight="Bold" Grid.Column="0" Foreground="Black" Text="{Binding Path=Title}" Name="title"/>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Column="1" Foreground="Black" Text="{Binding Path=Location}" Name="location"/>
<Image VerticalAlignment="Center" Grid.Column="2" Width="48" Height="48" Source="ApplicationIcon.jpg"/>
</Grid>
and here --> </Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can either change the ListBoxItem template, or, an easier approach is to change your ItemTemplate, You can simply add a divider within your ItemTemplate as follows:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<!-- your content goes here ... for example: -->
<TextBlock Text={Binding Path=InterestingThing}"/>
<!-- the divider -->
<Line X1="0" X2="200" Y1="0" Y2="0"
VerticalAlignment="Bottom"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

Resources