- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
像Winforms中一样,这似乎应该很简单,但是我对WPF还是比较陌生,因此仍在尝试改变对数据和UI交互方式的看法。
场景:用户在我的主窗体上单击一个按钮。该按钮用于输入街道地址。在街道地址表单中,当用户单击提交按钮时,我会进行一些基本数据验证。 Submit()遍历每个数据输入字段,并调用下面的方法来尝试提醒用户注意有问题的数据字段。
这是我没有执行任何可以检测到的代码:
private void FlashTextBox(RichTextBox box)
{
var currentBorderColor = box.BorderBrush;
var currentBackgroundColor = box.Background;
Task.Factory.StartNew(() =>
{
for (int x = 0; x < 5; x++)
{
this.Dispatcher.Invoke(() =>
{
box.Background = Brushes.Red;
box.BorderBrush = Brushes.IndianRed;
box.InvalidateVisual();
System.Threading.Thread.Sleep(100);
box.BorderBrush = currentBorderColor;
box.Background = currentBackgroundColor;
box.InvalidateVisual();
System.Threading.Thread.Sleep(100);
});
}
});
}
最佳答案
正如我提到的in my comment,代码的主要问题是您已阻止UI线程。因此,当您循环将感兴趣的属性更改为新值时,实际的UI永远不会有机会更新视觉表示,即屏幕上的内容。
具有讽刺意味的是,当您注意到“似乎在Winforms中应该很简单,就像在Winforms中一样”,如果您尝试在Winforms程序中编写相同的代码,那么您将遇到完全相同的问题。 Winforms和WPF(实际上,大多数GUI API)都具有完全相同的限制:只有一个线程可以处理所有UI,并且在更改一个或多个应该影响UI外观的数据值之后,您必须返回控件到调用您的UI线程,以便随后可以更新屏幕。
现在,您还注意到您正在“试图改变对数据和UI交互方式的看法”。这是一件好事,如果您愿意花时间学习WPF旨在使用的MVVM概念,那将会有很大帮助。 Winforms还具有数据绑定模型,实际上,您可以在Winforms中编写非常相似的代码,这是WPF强烈建议的。但是,WPF的“保留”图形模型与Winform的“立即”模型相反-即WPF跟踪图形的外观,而Winform要求您每次需要更新屏幕时都要自己处理图形-这很适合自己数据绑定方法要好得多,WPF的整个设计都基于此。
这意味着您应该努力将数据保留在数据所在的位置,将UI保留在UI所在的位置。即数据在您的代码隐藏中,而UI在XAML中。在这两个API中都是一个好主意,但是如果您无法使用WPF做到这一点,您将付出更多。
那么,这又在哪里留下您的问题呢?好吧,缺少一个很好的minimal, complete, and verifiable code example,很难知道您的代码是什么样子,因此什么是修复它的最佳方法。因此,相反,我将提供一些示例,希望您在重新定位代码以使其更好地适合WPF范例之后,可以按自己的喜好应用一个。 (不幸的是,我对WPF不太喜欢的一件事是,它在某些方面过于强大,提供了许多不同的方法来实现相同的结果;这有时有时真的很难知道什么是最好的方法。)
这两个示例在背后需要多少代码方面彼此不同。第一种将动画逻辑放入C#代码中,作为视图模型的一部分。一方面,这可以说不是“ WPF方式”。但是第二个使用视图代码(即XAML)来定义动画,这需要在视图代码的后面增加一些额外的内容,这使我有些烦恼,因为它模糊了视图和视图模型之间的界限。比我想要的多一点。
那好吧。
这是第一种方法的视图模型类:
class ViewModel : NotifyPropertyChangedBase
{
private string _text;
public string Text
{
get => _text;
set => _UpdateField(ref _text, value);
}
private bool _isHighlighted;
public bool IsHighlighted
{
get => _isHighlighted;
set => _UpdateField(ref _isHighlighted, value);
}
private bool _isAnimating;
public bool IsAnimating
{
get => _isAnimating;
set => _UpdateField(ref _isAnimating, value, _OnIsAnimatingChanged);
}
private void _OnIsAnimatingChanged(bool oldValue)
{
_toggleIsHighlightedCommand.RaiseCanExecuteChanged();
_animateIsHighlightedCommand.RaiseCanExecuteChanged();
}
private readonly DelegateCommand _toggleIsHighlightedCommand;
private readonly DelegateCommand _animateIsHighlightedCommand;
public ICommand ToggleIsHighlightedCommand => _toggleIsHighlightedCommand;
public ICommand AnimateIsHighlightedCommand => _animateIsHighlightedCommand;
public ViewModel()
{
_toggleIsHighlightedCommand = new DelegateCommand(() => IsHighlighted = !IsHighlighted, () => !IsAnimating);
_animateIsHighlightedCommand = new DelegateCommand(() => _FlashIsHighlighted(this), () => !IsAnimating);
}
private static async void _FlashIsHighlighted(ViewModel viewModel)
{
viewModel.IsAnimating = true;
for (int i = 0; i < 10; i++)
{
viewModel.IsHighlighted = !viewModel.IsHighlighted;
await Task.Delay(200);
}
viewModel.IsAnimating = false;
}
}
class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class DelegateCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
public DelegateCommand(Action execute, Func<bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public DelegateCommand(Action execute) : this(execute, null) { }
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => _canExecute?.Invoke() != false;
public void Execute(object parameter) => _execute?.Invoke();
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
NotifyPropertyChangedBase
只是我的视图模型的标准基类。它包含所有支持
INotifyPropertyChanged
接口的样板。有一些WPF框架本身包括此类基类。我不知道为什么WPF本身不提供一个。但是,这样做很方便,并且在它和粘贴到属性模板中的Visual Studio代码段之间,可以更快地将程序的视图模型放在一起。
DelegateCommand
使定义
ICommand
对象更加容易。同样,此类类型的类也可在第三方WPF框架中使用。 (我还有一个类的版本,该类具有通用的类型参数,该类型参数指定传递给
CanExecute()
和
Execute()
方法的命令参数的类型,但是由于在这里我们不需要它,所以我不必理会包括它。
Text
属性,因此我在UI中有一些绑定到
TextBox
的内容。它还具有与
bool
的视觉状态相关的几个
TextBox
属性。一个确定实际的视觉状态,而另一个确定当前是否处于动画状态。
ICommand
实例提供用户与视图模型的交互。一个只是切换视觉状态,而另一个则导致想要发生的动画。
IsAnimating
属性,然后循环十次以切换
IsHighlighted
属性。此方法使用
async
。在Winforms程序中,这是必不可少的,以便UI属性更新发生在UI线程中。但是在此WPF程序中,它是可选的。我喜欢async / await编程模型,但是对于简单的属性更改通知,WPF会根据需要将绑定更新封送回UI线程,因此您实际上可以在线程池中创建后台任务或专用线程来创建该任务。处理动画。
<Window x:Class="TestSO57403045FlashBorderBackground.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="clr-namespace:TestSO57403045FlashBorderBackground"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<StackPanel>
<Button Command="{Binding ToggleIsHighlightedCommand}" Content="Toggle Control" HorizontalAlignment="Left"/>
<Button Command="{Binding AnimateIsHighlightedCommand}" Content="Flash Control" HorizontalAlignment="Left"/>
<TextBox x:Name="textBox1" Width="100" Text="{Binding Text}" HorizontalAlignment="Left">
<TextBox.Style>
<p:Style TargetType="TextBox">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Background" Value="WhiteSmoke"/>
<p:Style.Triggers>
<DataTrigger Binding="{Binding IsHighlighted}" Value="True">
<Setter Property="BorderBrush" Value="IndianRed"/>
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</p:Style.Triggers>
</p:Style>
</TextBox.Style>
</TextBox>
</StackPanel>
</Window>
bool
的
true
值)。
{Binding}
的内容,这是对当前数据上下文的引用,在这种情况下,该上下文设置为我的视图模型类。
IsAnimating
属性,但是这次不是使用“ animate”命令来调用方法(该方法将此属性设置为副作用),而是直接设置了该属性,而没有执行其他操作(该属性现在动画的主要控制器仍然充当标志,以便可以根据需要启用/禁用按钮的命令):
class ViewModel : NotifyPropertyChangedBase
{
private string _text;
public string Text
{
get => _text;
set => _UpdateField(ref _text, value);
}
private bool _isAnimating;
public bool IsAnimating
{
get => _isAnimating;
set => _UpdateField(ref _isAnimating, value, _OnIsAnimatingChanged);
}
private void _OnIsAnimatingChanged(bool oldValue)
{
_animateIsHighlightedCommand.RaiseCanExecuteChanged();
}
private readonly DelegateCommand _animateIsHighlightedCommand;
public ICommand AnimateIsHighlightedCommand => _animateIsHighlightedCommand;
public ViewModel()
{
_animateIsHighlightedCommand = new DelegateCommand(() => IsAnimating = true, () => !IsAnimating);
}
}
<Window x:Class="TestSO57403045FlashBorderBackground.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="clr-namespace:TestSO57403045FlashBorderBackground"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<Window.Resources>
<Storyboard x:Key="flashBorder" RepeatBehavior="5x"
Completed="flashStoryboard_Completed">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
Duration="0:0:0.4">
<DiscreteColorKeyFrame KeyTime="0:0:0" Value="IndianRed"/>
<DiscreteColorKeyFrame KeyTime="0:0:0.2" Value="WhiteSmoke"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(BorderBrush).(SolidColorBrush.Color)"
Duration="0:0:0.4">
<DiscreteColorKeyFrame KeyTime="0:0:0" Value="Red"/>
<DiscreteColorKeyFrame KeyTime="0:0:0.2" Value="Black"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<StackPanel>
<Button Command="{Binding AnimateIsHighlightedCommand}" Content="Flash Control" HorizontalAlignment="Left"/>
<TextBox x:Name="textBox1" Width="100" Text="{Binding Text}" HorizontalAlignment="Left">
<TextBox.Style>
<p:Style TargetType="TextBox">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Background" Value="WhiteSmoke"/>
<p:Style.Triggers>
<DataTrigger Binding="{Binding IsAnimating}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource flashBorder}" Name="flashBorderBegin"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="flashBorderBegin"/>
</DataTrigger.ExitActions>
</DataTrigger>
</p:Style.Triggers>
</p:Style>
</TextBox.Style>
</TextBox>
</StackPanel>
</Window>
Storyboard
对象,其中包含两个动画序列(两个动画序列均同时启动),它们实际上是控件的闪烁。故事板本身使您可以指定应重复多少次(在这种情况下为
"5x"
五次),然后在每个动画序列中指定整个序列的持续时间(400毫秒,因为一个序列涉及两个状态,每个状态(在200毫秒内显示),然后是“关键帧”,该关键帧指示动画期间实际发生的情况,每个关键帧都指定动画在什么时间生效。
Completed
事件。在上一个示例中,默认的
MainWindow.xaml.cs
文件没有更改,但是对于此版本,有一些代码:
public partial class MainWindow : Window
{
private readonly ViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = (ViewModel)DataContext;
}
private void flashStoryboard_Completed(object sender, EventArgs e)
{
_viewModel.IsAnimating = false;
}
}
Storyboard.Completed
事件的事件处理程序的实现。而且由于该处理程序将需要修改视图模型状态,因此现在有代码从
DataContext
属性检索视图模型并将其保存在字段中,以便事件处理程序可以获取它。
IsAnimating
属性设置回
false
。
<ColorAnimationUsingKeyFrame/>
元素中的一个关键帧,而不是实际设置新颜色,只是删除了动画已应用的所有更改。)
关于c# - 如何在WPF中闪烁RichTextBox边框和背景色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57403045/
我是 Jetpack Compose 的新手。我目前正在开发一个聊天应用程序。我要求用户从图库中选择图像或从相机中拍照。然后我将文件 Uri 保存到数据库中,然后收听所有消息的列表。更新此列表时,此图
强制性代码,但 jsFiddle 准确地演示了这个问题。我有一个在 3 秒内扩大和淡出的圆圈。声纳风格是我的意图。问题是动画完成后它会快速“闪烁”然后重新开始。 请在此处查看问题:http://jsf
您好,我有一个多种颜色的 Logo ,我想将其用于随机/不稳定的故意闪烁效果。我只能找到其他关于使用淡入/淡出功能进行闪烁技巧的文章。关于如何用 css3 和/或 jQuery 做这样的技巧有什么想法
我正在使用 Swing 创建组件并使用 GLCanvas (com.jogamp.opengl.awt.GLCanvas) 创建我的窗口。 接下来就是问题了 在初始状态下,一切正常,但是当我拖动窗口调
我将 PhoneGap 2.2.0 与 jQuery Mobile 1.2.0 结合用于我在 Android 平台(版本 2.3.3 及更高版本)上的应用程序。在我使用固定标题的页面上,根本没有转换。
在我们使用 JavaScript 向页面添加图像或文本后,我们的网页在 iPad 上闪烁。我们尝试了 -webkit-backface-visibility:hidden; 的各种组合; -webki
有人能告诉我为什么在这个使用 SwingWorker 的简单演示中,屏幕闪烁,好像按钮不断跳跃一样? (关于改进多线程部分的反馈也值得赞赏)。 import java.awt.EventQueue;
我正在运行时从 CSV 文件向字符串网格添加多行,但是 StringGrid 在更新时似乎会闪烁很多,我认为会有一个 beginupadate/Endupdate 命令来停止此操作。但是我找不到它。有
我的窗口中有一个文本元素,我希望它每隔几秒或几毫秒闪烁一次或出现并消失。 我的代码是: import QtQuick 2.6 import QtQuick.Window 2.2 Window {
我的窗口中有一个文本元素,我希望它每隔几秒或几毫秒闪烁一次或出现并消失。 我的代码是: import QtQuick 2.6 import QtQuick.Window 2.2 Window {
我在UIButtons中有3个UIView,它们具有相同的文本颜色和相同的背景颜色。轻按三个按钮即可触发相应的事件。但是只有其中之一会响应触摸而“闪烁”。其他两个会发生什么?它们有时(但很少)具有“闪
我在 iOS 8 下实现 UIRefreshControl 时遇到了一种闪烁。每次我第一次到达 tableView 的顶部时(即应用程序刚刚启动时),我都会看到下面的 gif 中显示的闪烁。这不会发生
我希望有人能帮助我。我遇到以下问题: http://jsfiddle.net/zhPAF/ 标记: About Us
当鼠标悬停在图像“A”上时,尝试让图像“B”覆盖在图像“A”上。理想情况下,我希望它淡入。 HTML: jQuery:
我有一个 TabControl,我可以在其中添加/删除多个 TabPage。 当我添加足够多的页面以至于必须显示导航按钮时,我遇到了闪烁问题。 当导航按钮(左右导航的 2 个箭头)未显示时,我根本没有
我尝试实现自定义双缓冲,但它会导致闪烁。 这是控件(继承自Control的自定义控件)构造函数中的代码: bufferContext = new BufferedGraphicsContext();
我有以下代码: var footer = $('.footer'), extra = 0; // footer.css({ opacity: '0', display: 'block' });
我遇到了与 JPanel 中闪烁相关的问题。不知道为什么, window 里的球时不时地闪烁。我尝试了几种方法,比如双缓冲、BufferStrategy、Canvas,但都不起作用。主要思想是使用线程
我试图在 OpenGL 中绘制一些文本,而程序绘制立方体或任何 Opengl native ,因此,当我尝试将文本放在屏幕上时,它闪烁得非常快,我不知道为什么,我试图改变 sleep 值什么都没有..
我已经使用 LibGDX UI Setup 启动了一个项目。 我在 implements ApplicationListener 中唯一拥有的是: public void create() {
我是一名优秀的程序员,十分优秀!