I am having Storyboard in my Page resources to share it between required controls. I try to animate clicked ListItem using that Storyboard in code behind by setting TargetName propery.
<Page.Resources>
<Storyboard x:Name="Story1">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="-200"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<ListView x:Name="ListView1" IsItemClickEnabled="True" ItemClick="ListView1_ItemClick">
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="GridData">
<Grid.RenderTransform>
<TranslateTransform x:Name="GridTrans" X="0" />
</Grid.RenderTransform>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Price}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private void ListView1_ItemClick(object sender, ItemClickEventArgs e)
{
Story1.Stop();
var item = ListView1.ContainerFromItem(e.ClickedItem) as ListViewItem;
var grid = item.ContentTemplateRoot as Grid;
Storyboard.SetTargetName(Story1, grid.Name); //???
Story1.Begin();
}
But unable to animate clicked ListItem on ItemClick event. I get error as "Cannot resolve TargetName GridData"
The GridData is under DataTemplate, if you use SetTargetName method to set animation, it will not get correct ContentTemplateRoot. For your requirement, you could use SetTarget method.
private void ListView1_ItemClick(object sender, ItemClickEventArgs e)
{
Story1.Stop();
var item = ListView1.ContainerFromItem(e.ClickedItem) as ListViewItem;
var grid = item.ContentTemplateRoot as Grid;
Storyboard.SetTarget(Story1, grid);
Story1.Begin();
}
Related
I have a scenario where I have to generate create same StoryBoard Animation in Xaml for a set of data(which I will bind form ViewModel).
<Page
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
xmlns:miControls="using:Microsoft.UI.Xaml.Controls">
<Page.Resources>
<miControls:ItemsRepeater x:Name="repmeaterTest">
<miControls:ItemsRepeater.ItemTemplate>
<DataTemplate>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetName="DemoCircle" Storyboard.TargetProperty="(FrameworkElement.Width)">
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="50"/>
<EasingDoubleKeyFrame KeyTime="00:00:04" Value="250"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetName="DemoCircle" Storyboard.TargetProperty="(FrameworkElement.Height)">
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="50"/>
<EasingDoubleKeyFrame KeyTime="00:00:04" Value="250"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</DataTemplate>
</miControls:ItemsRepeater.ItemTemplate>
</miControls:ItemsRepeater>
</Page.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="clikToAnimate" Content="Animate" Click="clikToAnimate_Click" Margin="10"/>
<Ellipse Name="DemoCircle" Stroke="Purple" Width="50" Height="50" StrokeThickness="4" Fill="AntiqueWhite"/>
</StackPanel>
public sealed partial class MainPage : Page
{
List<int> noOfStoryBoard = new List<int> { 1,2,3,4,5};
public MainPage()
{
this.InitializeComponent();
}
private void clikToAnimate_Click(object sender, RoutedEventArgs e)
{
Storyboard1.Begin();
}
}
I want to generate StoryBoard dynamically for noOfStoryBoard(ie 5) in xaml
Does anyone have idea kindly share,
Here what i have tried to use items repeater
The request is that the row of my ListView blinks when the property SelectedItem of the ViewModel raises change.
This is my code, the problem is that it works only first time. Subsequent changes are ignored.
<DataTemplate x:Key="myDataTemplate">
<Grid x:Name="myGrid">
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding SelectedItem}" Value="True">
<Media:ControlStoryboardAction>
<Media:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation
To="#009ABF"
Storyboard.TargetName="myGrid"
Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"
AutoReverse="True"
Duration="0:0:1"
RepeatBehavior="1x" />
</Storyboard>
</Media:ControlStoryboardAction.Storyboard>
</Media:ControlStoryboardAction>
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<TextBlock Text="{Binding Name}"
Grid.Column="1"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Margin="0,2,10,0"
FontSize="16"
TextAlignment="Left"/>
<!--OMISSIS-->
</Grid>
SelectedItem code :
public bool SelectedItem
{
get
{
return this.selectedItem;
}
set
{
this.selectedItem = value;
this.RaisePropertyChanged();
}
}
This is the solution i found.
1) Use Completed event of the Storyboard
<Storyboard Completed="SelectedItemReset" FillBehavior="Stop">
3) Use the GalaSoft.MvvmLight.Messaging.Messenger to comunicate from CodeBehind and ViewModel the reset of the property SelectedItem
Xaml
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="DataTemplateGrid">
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding SelectedItem}" ComparisonCondition="Equal" Value="True">
<Media:ControlStoryboardAction ControlStoryboardOption="Play">
<Media:ControlStoryboardAction.Storyboard>
<Storyboard Completed="SelectedItemReset" FillBehavior="Stop">
<ColorAnimation
To="Lime"
Storyboard.TargetName="DataTemplateGrid"
Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"
Duration="0:0:1"/>
</Storyboard>
</Media:ControlStoryboardAction.Storyboard>
</Media:ControlStoryboardAction>
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<!--OMISSIS-->
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
CodeBehind
private void SelectedItemReset(object sender, object e)
{
GalaSoft.MvvmLight.Messaging.Messenger.Default.Send<Mvvm.ViewModels.Units.SelectedItemResetMessage>(new Mvvm.ViewModels.Units.SelectedItemResetMessage());
}
MVVM Class .ctor
public MyViewModel()
{
GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<SelectedItemResetMessage>(this, message =>
{
if (this.SelectedItem == true)
this.SelectedItem = false;
});
}
Note: My DataTemplate was in a separate file and linked to the ListView with the ItemTemplate property, this prevented me from calling the method Completed in CodeBehind.
I want to animate input box just like the one above how to do it in MVVM template 10
I have a list view
and need the search bar just like the image
I have attached an solution to your problem. There are two storyboards that are triggered on GotFocus and Lost Focus for an AutoSuggestBox in UWP c#
Here us what I achieved:
XAML :
<Page.Resources>
<Storyboard x:Name="OnCancel">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="70">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="51"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-36.058"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="OnTextBoxFocus">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="button">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="70">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Duration="0:0:0.4" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="HeaderGrid" d:IsOptimized="True"/>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="-36.058"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid x:Name="HeaderGrid" Margin="0,0,-1,-0.117" RenderTransformOrigin="0.5,0.5" Height="51">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="TextBlock" Margin="5,0,1,3" FontSize="36" SelectionHighlightColor="{x:Null}" Foreground="DodgerBlue"/>
<TextBox Width="1" Height="1" IsReadOnly="True"/>
<Path Data="M0,48 L360,48" Height="1" Margin="0,0,0,0.117" Stretch="Fill" Stroke="DodgerBlue" UseLayoutRounding="False" VerticalAlignment="Bottom" d:LayoutOverrides="LeftPosition, RightPosition"/>
</Grid>
<StackPanel Grid.Row="1">
<Grid Height="32" Margin="12,8,12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<AutoSuggestBox x:Name="searchText" PlaceholderText="Search" QueryIcon="Find" TextMemberPath="name" LostFocus="searchText_LostFocus" GotFocus="searchText_GotFocus"/>
<Button x:Name="button" Content="Cancel" VerticalAlignment="Stretch" d:LayoutOverrides="Height" Grid.Column="4" Margin="5,0,0,0" Width="70" Click="button_Click"/>
</Grid>
<ListView x:Name="listView" Background="#FFECECEC" Margin="0,8,0,0">
<ListViewItem Content="List View Item 1" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 2" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 3" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 4" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 5" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 6" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 7" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 8" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 9" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
<ListViewItem Content="List View Item 10" BorderThickness="0,0,0,1" BorderBrush="#FFB9B9B9"/>
</ListView>
</StackPanel>
</Grid>
and in code behind XAML.CS
private void searchText_LostFocus(object sender, RoutedEventArgs e)
{
OnCancel.Begin();
}
private void button_Click(object sender, RoutedEventArgs e)
{
OnCancel.Begin();
}
private void searchText_GotFocus(object sender, RoutedEventArgs e)
{
OnTextBoxFocus.Begin();
}
Also dont forget to set width of button = 0 on Initialization.
Hope this helps.
You can use data binding to bind your title and Cancel button's Visibility property to property defined in your ViewModel, as #Raunaq Patel said, the animations are triggered by GotFocus and LostFocus event.
So you can for example code like this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="pageHeader" Text="Main Page" Grid.Row="0" Visibility="{Binding IsVisible}" FontSize="30" />
<Grid Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<AutoSuggestBox HorizontalAlignment="Stretch" GotFocus="{x:Bind ViewModel.Search_GotFocus}"
LostFocus="{x:Bind ViewModel.Search_LostFocus}" VerticalAlignment="Stretch"
Width="{Binding BoxWidth}" />
<TextBlock Text="Cancel" Foreground="BlueViolet" Tapped="{x:Bind ViewModel.Cancel_Tapped}" Width="100"
VerticalAlignment="Stretch" HorizontalAlignment="Center" FontSize="20"
Visibility="{Binding CancelIsVisible}" Grid.Column="1" />
</Grid>
<ListView Grid.Row="1" IsEnabled="{Binding ListViewEnable}">
<ListViewItem>Item 1</ListViewItem>
<ListViewItem>Item 2</ListViewItem>
<ListViewItem>Item 3</ListViewItem>
<ListViewItem>Item 4</ListViewItem>
<ListViewItem>Item 5</ListViewItem>
</ListView>
</Grid>
</Grid>
Since you are using Template 10, code behind is for example in the MainPageViewModel like this:
public class MainPageViewModel : ViewModelBase
{
private Visibility _IsVisible;
public Visibility IsVisible
{
get { return _IsVisible; }
set
{
if (value != _IsVisible)
{
_IsVisible = value;
RaisePropertyChanged();
}
}
}
private Visibility _CancelIsVisible;
public Visibility CancelIsVisible
{
get { return _CancelIsVisible; }
set
{
if (value != _CancelIsVisible)
{
_CancelIsVisible = value;
RaisePropertyChanged();
}
}
}
private bool _ListViewEnable;
public bool ListViewEnable
{
get { return _ListViewEnable; }
set
{
if (value != _ListViewEnable)
{
_ListViewEnable = value;
RaisePropertyChanged();
}
}
}
private double _BoxWidth;
public double BoxWidth
{
get { return _BoxWidth; }
set
{
if (value != _BoxWidth)
{
_BoxWidth = value;
RaisePropertyChanged();
}
}
}
public MainPageViewModel()
{
_IsVisible = Visibility.Visible;
_CancelIsVisible = Visibility.Collapsed;
_ListViewEnable = true;
_BoxWidth = Window.Current.Bounds.Width;
}
public void Search_GotFocus(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
IsVisible = Visibility.Collapsed;
CancelIsVisible = Visibility.Visible;
ListViewEnable = false;
BoxWidth = _BoxWidth - 100;
}
public void Search_LostFocus(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
IsVisible = Visibility.Visible;
CancelIsVisible = Visibility.Collapsed;
ListViewEnable = true;
BoxWidth = Window.Current.Bounds.Width;
}
public void Cancel_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
IsVisible = Visibility.Visible;
CancelIsVisible = Visibility.Collapsed;
ListViewEnable = true;
BoxWidth = Window.Current.Bounds.Width;
}
}
Here you can see the data in ListView are fake, you can of course use DataTemplate and bind collection to the ItemSource of the ListView. Here is the rendering image of my sample:
It's AutoSuggestBox.
You can see how to use in https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlAutoSuggestBox
And you can see summary on https://msdn.microsoft.com/zh-cn/windows/uwp/controls-and-patterns/auto-suggest-box?f=255&MSPPError=-2147217396
How can i do that by xaml triggers?
If you want to generate graphicaly, open your project in Blend.
Open the Trigger Tab (third tab)
+Event
In the When section , select the textbox you gave a name to, and the event LostFocus (or GotFocus)
Click on the + right of "is raised" to create a storyboard
In the object and timelines windows, select textbox, and select a point at 200ms ( 2 lines right)
Then in the property windows, Transform section, apply the rotation :
For the textbox in the property windows, LayoutTransform section, edit :
-center of rotation in the fifth tab (0;0)
-Angle of rotation in the second tab (-90)
Here is the resulting code :
<Window x:Class="DemoRotateWithTrigger.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Storyboard x:Key="OnLostFocus1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="textboxToBeRotated">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="-90"/>
</DoubleAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="textboxToBeRotated">
<EasingPointKeyFrame KeyTime="0:0:0.2" Value="0,0"/>
</PointAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnGotFocus1">
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="textboxToBeRotated">
<EasingPointKeyFrame KeyTime="0:0:0.2" Value="0,0"/>
</PointAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="textboxToBeRotated">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="UIElement.LostFocus" SourceName="textboxToBeRotated">
<BeginStoryboard Storyboard="{StaticResource OnLostFocus1}"/>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.GotFocus" SourceName="textboxToBeRotated">
<BeginStoryboard x:Name="OnGotFocus1_BeginStoryboard" Storyboard="{StaticResource OnGotFocus1}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<TextBox x:Name="textboxToBeRotated" HorizontalAlignment="Left" Height="23" Margin="138,158,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0,0">
<TextBox.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-90"/>
<TranslateTransform/>
</TransformGroup>
</TextBox.RenderTransform>
</TextBox>
<Button Content="Button" HorizontalAlignment="Left" Margin="75,219,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
Good luck
Set RenderTransformOrigin = new Point(0, 0) and set initial RenderTransform = new RotateTransform(-90) in Loaded event of window, then set it to 0 in GotFocus and again -90 in LostFocus.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.TextBox1.RenderTransformOrigin = new Point(0, 0);
this.TextBox1.RenderTransform = new RotateTransform(-90);
}
private void TextBox1_GotFocus(object sender, RoutedEventArgs e)
{
this.TextBox1.RenderTransform = new RotateTransform(0);
}
private void TextBox1_LostFocus(object sender, RoutedEventArgs e)
{
this.TextBox1.RenderTransform = new RotateTransform(-90);
}
Remember to have another control in window to test LostFocus.
I'm building a Windows Store app with C#/XAML.
I have a simple ListView bound to an ItemsSource. There's a DataTemplate which defines the structure of each item and that has a ContentControl and a TextBlock in it.
I wish to change the Foreground colour of the TextBlock when the item is selected. Does anyone know how I can do this?
<ListView Grid.Column="1"
ItemsSource="{Binding Categories}"
ItemContainerStyle="{StaticResource CategoryListViewItemStyle}"
Background="{StaticResource DeepRedBrush}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding Id, Converter={StaticResource Cat2Icon}}" HorizontalAlignment="Left" VerticalAlignment="Center" Width="110" Foreground="#FF29BCD6"/>
<TextBlock x:Name="catName" HorizontalAlignment="Left" Margin="0" TextWrapping="Wrap" Text="{Binding Name}" Grid.Column="1" VerticalAlignment="Center" FontSize="18.667"
Foreground="White"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
At the moment it's set to "White", so all I need is some binding expression that will change the Foreground property depending on the selected state of the item in the listview.
This does what you are asking for.
Using this XAML
<Grid x:Name="LayoutRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="MyListView" ItemsSource="{Binding Items}" SelectionMode="Single" SelectedItem="{Binding Selected, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Height="100" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Ellipse x:Name="ellipse">
<Ellipse.Fill>
<SolidColorBrush Color="{Binding Color}" />
</Ellipse.Fill>
</Ellipse>
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="10" Text="{Binding Title}" Style="{StaticResource HeaderTextBlockStyle}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
And this code behind:
public class MyModel : BindableBase
{
string _Title = default(string);
public string Title { get { return _Title; } set { SetProperty(ref _Title, value); } }
Color _Color = Colors.White;
public Color Color { get { return _Color; } set { SetProperty(ref _Color, value); } }
}
public class MyViewModel : BindableBase
{
public MyViewModel()
{
var items = Enumerable.Range(1, 10)
.Select(x => new MyModel { Title = "Title " + x.ToString() });
foreach (var item in items)
this.Items.Add(item);
}
MyModel _Selected = default(MyModel);
public MyModel Selected
{
get { return _Selected; }
set
{
if (this.Selected != null)
this.Selected.Color = Colors.White;
SetProperty(ref _Selected, value);
value.Color = Colors.Red;
}
}
ObservableCollection<MyModel> _Items = new ObservableCollection<MyModel>();
public ObservableCollection<MyModel> Items { get { return _Items; } }
}
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (!object.Equals(storage, value))
{
storage = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
It will update your data template for you.
I want to make this quick point: updating the content of your list through the ViewModel is the easiest and most light-weight approach. In this case, I am updating the color which is bound to the ellipse. However, if this were a complex set of changes, I might just set a style instead. Another option is to hide and show an entire set of controls in the template. You cannot, however, change the data template because it will not be re-rendered until the grid re-draws, and that's not what you want to do.
Just like changing the Ellipse color, you could change the TextBlock Foreground like you asked in your question. Either way, this gets you what you want in the most elegant way.
Best of luck!
You can simply handle the SelectionChanged event on the ListView and change the Foreground of the previously selected item and the newly selected item by either changing a view model value on SelectedItem that is bound to your Foreground.
You can also find the TextBlock using ListView.ItemContainerGenerator.ContainerFromItem(ListView.SelectedItem) + VisualTreeHelper as in Jerry Nixon's blog post and changing the Foreground directly, though that technique has a problem if your ListView is virtualized (which it is by default), since if you scroll away from the selected item and back - the item view with the changed Foreground might be recycled and used for another item in your collection.
Another option is to bind the Foreground to the IsSelected property of the parent ListViewItem which you can do in many ways as well. You could for example put your entire DataTemplate in a UserControl and bind the Foreground to the Parent of that control. The problem is I think Parent is not a dependency property and I see no ParentChanged event on FrameworkElement (base class for UserControl that defines the Parent property), so it might be tough to go this route. Another way to bind these is to define an attached dependency property or behavior that would set up that binding for you, but that is complicated (though I have already created one you could use here).
Finally you could modify your ListView.ItemContainerStyle and change the SelectedBackground value. If that works - it would be the ideal solution.
<Style TargetType="ListViewItem">
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="IsHoldingEnabled" Value="True"/>
<Setter Property="Margin" Value="0,0,18,2"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter CheckHintBrush="{ThemeResource ListViewItemCheckHintThemeBrush}" CheckBrush="{ThemeResource ListViewItemCheckThemeBrush}" ContentMargin="4" ContentTransitions="{TemplateBinding ContentTransitions}" CheckSelectingBrush="{ThemeResource ListViewItemCheckSelectingThemeBrush}" DragForeground="{ThemeResource ListViewItemDragForegroundThemeBrush}" DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}" DragBackground="{ThemeResource ListViewItemDragBackgroundThemeBrush}" DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}" FocusBorderBrush="{ThemeResource ListViewItemFocusBorderThemeBrush}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" PointerOverBackgroundMargin="1" PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" PointerOverBackground="{ThemeResource ListViewItemPointerOverBackgroundThemeBrush}" ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" SelectedPointerOverBorderBrush="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}" SelectionCheckMarkVisualEnabled="True" SelectedForeground="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" SelectedPointerOverBackground="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}" SelectedBorderThickness="{ThemeResource ListViewItemCompactSelectedBorderThemeThickness}" SelectedBackground="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>