c# – 使用MVVM模式更新WPF中VisualCollection主机中的DrawingVi
我正在使用
WPF中的一个项目,每秒更新视图30次.据我所知,我正在使用MVVM模式,并且对目前的结果非常满意.但是,我想知道是否有更有效的方法来更新我的主机容器中的VisualCollection内的DrawingVisuals.在我的viewmodel中的每个属性更改中,我发现,删除然后为该viewmodel重新添加一个新的DrawingVisual.随着不断移动的对象,我觉得应该有更好的方法,比如将DrawingVisuals本身直接绑定到viewmodel的属性,但是看起来会是什么样的?随着模拟中模型数量的增加,我需要确保我有一个简化的更新工作流程.我开始关注这个例子:
http://msdn.microsoft.com/en-us/library/ms742254.aspx
我故意避免DependencyProperties并将UserControls绑定到每个viewmodel,因为我需要一个非常有效的绘图画布(因此下面的QuickCanvas).因此除了设计主UI和连接按钮和命令之外,我几乎不需要XAML.请问是否有些事情似乎不清楚或我遗漏了一些重要的事情.谢谢! 可视主机容器(视图): public partial class QuickCanvas : FrameworkElement { private readonly VisualCollection _visuals; private readonly Dictionary<Guid,DrawingVisual> _visualDictionary; public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource",typeof(ObservableNotifiableCollection<IVisualModel>),typeof(QuickCanvas),new PropertyMetadata(OnItemsSourceChanged)); public QuickCanvas() { InitializeComponent(); _visuals = new VisualCollection(this); _visualDictionary = new Dictionary<Guid,DrawingVisual>(); } public ObservableNotifiableCollection<IVisualModel> ItemsSource { set { SetValue(ItemsSourceProperty,value); } get { return (ObservableNotifiableCollection<IVisualModel>)GetValue(ItemsSourceProperty); } } protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.Property.Name == "Width" || e.Property.Name == "Height" || e.Property.Name == "Center") { UpdateVisualChildren(); } } private void UpdateVisualChildren() { if (ItemsSource == null || _visuals.Count == 0) return; foreach (var model in ItemsSource) { var visual = FindVisualForModel(model); if (visual != null) { UpdateVisualFromModel(visual,model); } } } private void UpdateVisualPairFromModel(DrawingVisual visual,IVisualModel model) { visual.Transform = ApplyVisualTransform(visual.Transform,model); } private static void OnItemsSourceChanged(DependencyObject obj,DependencyPropertyChangedEventArgs args) { (obj as QuickCanvas).OnItemsSourceChanged(args); } private void OnItemsSourceChanged(DependencyPropertyChangedEventArgs args) { _visuals.Clear(); if (args.OldValue != null) { var models = args.OldValue as ObservableNotifiableCollection<IVisualModel>; models.CollectionCleared -= OnCollectionCleared; models.CollectionChanged -= OnCollectionChanged; models.ItemPropertyChanged -= OnItemPropertyChanged; } if (args.NewValue != null) { var models = args.NewValue as ObservableNotifiableCollection<IVisualModel>; models.CollectionCleared += OnCollectionCleared; models.CollectionChanged += OnCollectionChanged; models.ItemPropertyChanged += OnItemPropertyChanged; CreateVisualChildren(models); } } private void OnCollectionCleared(object sender,EventArgs args) { _visuals.Clear(); _visualDictionary.Clear(); } private void OnCollectionChanged(object sender,NotifyCollectionChangedEventArgs args) { if (args.OldItems != null) RemoveVisualChildren(args.OldItems); if (args.NewItems != null) CreateVisualChildren(args.NewItems); } private void OnItemPropertyChanged(object sender,ItemPropertyChangedEventArgs args) { var model = args.Item as IVisualModel; if (model == null) throw new ArgumentException("args.Item was expected to be of type IVisualModel but was not."); //TODO is there a better way to update without having to add/remove visuals? var visual = FindVisualForModel(model); _visuals.Remove(visual); visual = CreateVisualFromModel(model); _visuals.Add(visual); _visualDictionary[model.Id] = visual;** } private DrawingVisual FindVisualForModel(IVisualModel model) { return _visualDictionary[model.Id]; } private void CreateVisualChildren(IEnumerable models) { foreach (IVisualModel model in models) { var visual = CreateVisualFromModel(model); _visuals.Add(visual); _visuals.Add(visual); _visualDictionary.Add(model.Id,visual); } } private DrawingVisual CreateVisualFromModel(IVisualModel model) { var visual = model.GetVisual(); UpdateVisualFromModel(visual,model); return visual; } private void RemoveVisualChildren(IEnumerable models) { foreach (IVisualModel model in models) { var visual = FindVisualForModel(model); if (visual != null) { _visuals.Remove(visual); _visualDictionary.Remove(model.Id); } } } protected override int VisualChildrenCount { get { return _visuals.Count; } } protected override Visual GetVisualChild(int index) { if (index < 0 || index >= _visuals.Count) throw new ArgumentOutOfRangeException("index"); return _visuals[index]; } } IVisuaModel impl: public class VehicleViewModel : IVisualModel { private readonly Vehicle _vehicle; private readonly IVisualFactory<VehicleViewmodel> _visualFactory; private readonly IMessageBus _messageBus; public VehicleViewmodel(Vehicle vehicle,IVisualFactory<VehicleViewmodel> visualFactory,IMessageBus messageBus) { _vehicle = vehicle; _visualFactory = visualFactory; _messageBus = messageBus; _messageBus.Subscribe<VehicleMovedMessage>(VehicleMoveHandler,Dispatcher.CurrentDispatcher); Id = Guid.NewGuid(); } public void Dispose() { _messageBus.Unsubscribe<VehicleMovedMessage>(VehicleMoveHandler); } private void VehicleMoveHandler(VehicleMovedMessage message) { if (message.Vehicle.Equals(_vehicle)) OnPropertyChanged(""); } public Guid Id { get; private set; } public Point Anchor { get { return _vehicle.Position; } } public double Rotation { get { return _vehicle.Orientation; } } public DrawingVisual GetVisual() { return _visualFactory.Create(this); } public double Width { get { return _vehicle.VehicleType.Width; } } public double Length { get { return _vehicle.VehicleType.Length; } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) handler(this,new PropertyChangedEventArgs(propertyName)); } } IVisualFactory impl: public class VehicleVisualFactory : IVisualFactory<VehicleViewModel> { private readonly IDictionary<string,Pen> _pens; private readonly IDictionary<string,Brush> _brushes; public VehicleVisualFactory(IDictionary<string,Pen> pens,IDictionary<string,Brush> brushes) { _pens = pens; _brushes = brushes; } public DrawingVisual Create(VehicleViewmodel viewModel) { var result = new DrawingVisual(); using (var context = result.RenderOpen()) { context.DrawRectangle(_brushes["VehicleGreen"],_pens["VehicleDarkGreen"],new Rect(-viewModel.Width / 2,-viewModel.Length / 2,viewModel.Width,viewModel.Length)); } return result; } } 解决方法
我发现你在阅读你的帖子时非常有趣且巧妙地做了.我已经用wpf和“实时”问题进行了一些实验,这里有一些我可以根据自己的经验带来的东西:
>我不建议您使用视图模型的完整绑定视图,特别是如果车辆数量不同,您的车辆的属性.实际上,只有在初始化之后,绑定机制才会非常快.初始化确实很慢.因此,如果您倾向于使用此类机制,我建议您使用池来尽可能避免绑定分配.关于它的外观问题的问题……我猜所有与装订有关的事情都会在c#(http://msdn.microsoft.com/en-us/library/ms742863.aspx)的车辆工厂进行? 希望这有点帮助.如果有一些你不理解的点或者你只是不同意,请不要犹豫.请告知我们,我对您的选择非常感兴趣! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |