I have a list of items that is represented by separate view models. Each view model is listening to network event. I want to flash the background of a listview item when a specific error happen. I have tried using visual state groups with state triggers but it doesn't seem to work for me.
Here is what I have tried - MainWindow.xaml
:
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="FlashingTest.MainWindow"
xmlns=";
xmlns:x=";
xmlns:local="using:FlashingTest"
xmlns:d=";
xmlns:mc=";
mc:Ignorable="d"
Title="FlashingTest">
<ListView ItemsSource="{x:Bind ViewModel.Items}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:TestItemViewModel">
<Border
Margin="0,2,0,0"
MinHeight="30"
MinWidth="300"
>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Flashing">
<VisualState>
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding Flashing}" />
</VisualState.StateTriggers>
<Storyboard>
<ColorAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"
To="GreenYellow"
AutoReverse="True"
/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock Text="{x:Bind Text}" />
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Window>
MainWindow.xaml.cs
:
public sealed partial class MainWindow : Window
{
public MainViewModel ViewModel
{
get;
} = new();
public MainWindow()
{
this.InitializeComponent();
this.ViewModel.Items.Add(new()
{
Text = "First"
});
this.ViewModel.Items.Add(new()
{
Text = "Second"
});
this.ViewModel.Items.Add(new()
{
Text = "Third"
});
}
}
MainViewModel.cs
:
public class MainViewModel
{
public ObservableCollection<TestItemViewModel> Items
{
get;
} = new();
}
TestItemViewModel.cs
(network event simulated with a timer)
public class TestItemViewModel : INotifyPropertyChanged
{
private readonly DispatcherTimer _timer;
private bool _flashing = false;
public event PropertyChangedEventHandler PropertyChanged;
public bool Flashing
{
get => _flashing;
set => SetProperty(ref _flashing, value);
}
public TestItemViewModel()
{
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(250);
_timer.Tick += (s, e) =>
{
if (Random.Shared.Next() % 3 == 0)
Flashing = true;
};
_timer.Start();
}
public string Text
{
get; set;
}
protected void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have a list of items that is represented by separate view models. Each view model is listening to network event. I want to flash the background of a listview item when a specific error happen. I have tried using visual state groups with state triggers but it doesn't seem to work for me.
Here is what I have tried - MainWindow.xaml
:
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="FlashingTest.MainWindow"
xmlns="http://schemas.microsoft/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft/winfx/2006/xaml"
xmlns:local="using:FlashingTest"
xmlns:d="http://schemas.microsoft/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats./markup-compatibility/2006"
mc:Ignorable="d"
Title="FlashingTest">
<ListView ItemsSource="{x:Bind ViewModel.Items}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:TestItemViewModel">
<Border
Margin="0,2,0,0"
MinHeight="30"
MinWidth="300"
>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Flashing">
<VisualState>
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding Flashing}" />
</VisualState.StateTriggers>
<Storyboard>
<ColorAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"
To="GreenYellow"
AutoReverse="True"
/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock Text="{x:Bind Text}" />
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Window>
MainWindow.xaml.cs
:
public sealed partial class MainWindow : Window
{
public MainViewModel ViewModel
{
get;
} = new();
public MainWindow()
{
this.InitializeComponent();
this.ViewModel.Items.Add(new()
{
Text = "First"
});
this.ViewModel.Items.Add(new()
{
Text = "Second"
});
this.ViewModel.Items.Add(new()
{
Text = "Third"
});
}
}
MainViewModel.cs
:
public class MainViewModel
{
public ObservableCollection<TestItemViewModel> Items
{
get;
} = new();
}
TestItemViewModel.cs
(network event simulated with a timer)
public class TestItemViewModel : INotifyPropertyChanged
{
private readonly DispatcherTimer _timer;
private bool _flashing = false;
public event PropertyChangedEventHandler PropertyChanged;
public bool Flashing
{
get => _flashing;
set => SetProperty(ref _flashing, value);
}
public TestItemViewModel()
{
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(250);
_timer.Tick += (s, e) =>
{
if (Random.Shared.Next() % 3 == 0)
Flashing = true;
};
_timer.Start();
}
public string Text
{
get; set;
}
protected void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Share
Improve this question
edited Mar 22 at 8:54
marc_s
756k184 gold badges1.4k silver badges1.5k bronze badges
asked Mar 22 at 7:36
yasaryasar
13.7k30 gold badges97 silver badges170 bronze badges
1
- You have a "Border" and a "Border.Background" in your template; you do not have a "Panel" (e.g. Grid) in your template. – Gerry Schmitz Commented Mar 22 at 16:57
1 Answer
Reset to default 0 +50The following works on my end:
- Name the
Border
. - Set the
Border
as target for the animation. - Use
UserControl
as a wrapper. - Change
Panel
toBorder
as suggested on the comments. - Set the
Border
'sBackground
toTransparent
. (Not sure why it doesn't work without this).
<ListView
ItemsSource="{x:Bind ViewModel.Items}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:TestItemViewModel">
<UserControl>
<Border x:Name="RootBorder"
MinWidth="300"
MinHeight="30"
Margin="0,2,0,0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind Flashing, Mode=OneWay}" />
</VisualState.StateTriggers>
<Storyboard>
<ColorAnimation
AutoReverse="True"
Storyboard.TargetName="RootBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="GreenYellow"
Duration="0:0:0.3" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock Text="{x:Bind Text}" />
</Border>
</UserControl>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Instead of wrapping it with a UserControl
, creating a custom control should be a better idea to avoid performance issues.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744322661a4568496.html
评论列表(0条)