我无法找到一个简单的例子来说明如何在网上实现这一点,我能理解。我也不想使用MvvmLight。
我的视图包含一个矩形,其填充颜色绑定到视图模型中的SolidColorBrush属性。
我的模型还有一个SolidColorBrush属性和一个UpdateBrushColor方法。
我希望我的视图模型运行一个后台线程,可以在模型中调用UpdateBrushColor,然后更新自己的SolidColorBrush以匹配模型画笔颜色,然后通过数据绑定更新UI。
我在后台使用Dispatcher.Invoke来更新UI但仍然得到异常:'必须在与DependencyObject相同的线程上创建DependencySource。
查看(仅限控件)
<StackPanel VerticalAlignment="Center">
<Rectangle Height="50"
Width="50"
Fill="{Binding Brush}">
</Rectangle>
<CheckBox></CheckBox>
</StackPanel>
模型
class Model
{
public SolidColorBrush Brush { get; set; } = Brushes.Black;
public void UpdateBrushColor()
{
Thread.Sleep(100);
Random rnd = new Random();
byte r = (byte)rnd.Next(0, 255);
byte g = (byte)rnd.Next(0, 255);
byte b = (byte)rnd.Next(0, 255);
Brush = new SolidColorBrush(Color.FromArgb(255, r, g, b));
}
}
查看模型
class Vm : INotifyPropertyChanged
{
public Model Model { get; set; }
private SolidColorBrush brush;
public SolidColorBrush Brush
{
get { return brush; }
set { SetProperty(ref brush, value); }
}
public Vm()
{
Model = new Model();
Task.Factory.StartNew(() =>
{
while (true)
{
Model.UpdateBrushColor();
Application.Current.Dispatcher.Invoke(() =>
{
Brush = Model.Brush; // why can't access model from here?
});
}
});
}
// Data Binding Implementation
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
NotifyPropertyChanged(propertyName);
return true;
}
}
答案 0 :(得分:3)
不要在模型中使用Brush类,因为它是从DispatcherObject派生的,因此具有线程关联性。在任务的线程中创建的实例不能在UI线程中使用。
您可以使用Color
,这是一种没有线程关联的结构类型。
除此之外,您还可以使用简单的DispatcherTimer进行循环更新:
public class Model
{
private readonly Random random = new Random();
public Color Color { get; private set; }
public void UpdateColor()
{
Color = Color.FromRgb(
(byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(256));
}
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Model Model { get; } = new Model();
private Brush brush;
public Brush Brush
{
get { return brush; }
set
{
brush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Brush)));
}
}
public ViewModel()
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(0.1)
};
timer.Tick += (s, e) =>
{
Model.UpdateColor();
Brush = new SolidColorBrush(Model.Color);
};
timer.Start();
}
}