0

我没有经常使用 wpf,并认为在运行时更改椭圆的颜色将是一个简单的过程。我有一个 FileWatcher,在创建的事件中,我想将椭圆的颜色更改为一种颜色,然后再变回来,创建一个闪烁的效果。(created是椭圆,br4是xaml中定义的纯色画笔)

    public void watcherCreated(object seneder, FileSystemEventArgs e)
    {

        Application.Current.Resources["br4"] = new SolidColorBrush(Colors.Green);
        created.Fill = (SolidColorBrush)Application.Current.Resources["br4"];

    }

一旦在触发事件的路径中创建文件,我就会收到此错误:无效操作异常调用线程无法访问此对象,因为不同的线程拥有它。我一直在寻找使用 freeze() 方法的解决方案,但没有成功。

     created.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
            delegate()
            {
                Application.Current.Resources["br4"] = new SolidColorBrush(Colors.Green);
                created.Fill = (SolidColorBrush)Application.Current.Resources["br4"];
            }
        ));

收到谢谢评论

4

3 回答 3

1

您只能从创建它们的同一线程访问 UI 元素。

您应该使用 Dispatcher.Invoke 或 Dispatcher.BeginInvoke 在 UI 线程上调用一个委托……然后您可以在其中访问“已创建”元素的“填充”属性。

有关问题的说明,请参阅此链接:

而不是尝试在 UI 中设置不断变化的颜色......您可以做的是在您的 ViewModel 上公开一个包含状态的属性。

当您的 FileWatcher 通知您新创建的文件(通过调用 watcherCreated 方法)时,您只需在 ViewModel 中设置该状态。

在您的 UI 中...使用带有转换器的绑定来绑定到您的 ViewModel 中的 state 属性。转换器将根据状态确定要使用的画笔,例如,如果状态为 1,则返回绿色画笔,如果状态为 0,则返回红色画笔。

要将状态重置回“关闭”位置......您可以有一个计时器,在 1 秒后等......将状态值设置回关闭。

通过这样做....您将状态与 UI 分开。

如果将来您想要一种更复杂的方式在 UI 中显示状态...例如,有一个动画(使用 StoryBoards/Visual State Manager)逐渐从绿色变回红色...那么您可以拥有该动画再次基于 ViewModel 中的状态触发。

于 2012-08-17T12:00:18.993 回答
1

在 WPF 中,所有 UI 控件都在不同的线程中加载,而您的应用程序在单独的线程中运行。

因此,请认为您收到此错误是因为您的应用程序(主线程)正在尝试访问UIThread中的 Elipse 。这是不允许的,因为线程不能直接访问彼此的对象。

因此 WPF 引入了调度程序对象。使用以下

if (this.Dispatcher.Thread != System.Threading.Thread.CurrentThread)
{
    this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(
            delegate()
            {
                Application.Current.Resources["br4"] = new SolidColorBrush(Colors.Green);
                created.Fill = (SolidColorBrush)Application.Current.Resources["br4"];
            }
            ));
}
于 2012-08-17T12:07:46.993 回答
0

更简单的解决方案是在 UI 线程本身上设置 created.Fill。您将不需要 Dispatcher.Invoke 或 Dispatcher.BeginInvoke。

于 2012-08-17T12:05:02.680 回答