我正在尝试学习MVVM样式更新。不是那么游泳。
我不得不更新一个基于对Point Collection的更改而绘制的简单矩形。 在初始化时,UI更新,但在对Point Collection进行简单更改后,UI中的路径不会更新。
我添加了一些TextBlock来确保Change事件被触发,但此时我有点迷失。
任何帮助表示赞赏:
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ExampleGreg" x:Class="ExampleGreg.MainWindow"
Title="MainWindow" Height="161.614" Width="324.087">
<Grid x:Name="gridUser" MouseDown="click_MouseDown" >
<Canvas x:Name="MeterCanvas" Margin="14,7,30,0" Background="#FFAFAFAF" Height="35" VerticalAlignment="Top">
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry x:Name="geometry"/>
</Path.Data>
</Path>
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry x:Name="polylinePwr">
<PathGeometry.Transform>
<ScaleTransform ScaleX="{Binding ActualWidth, ElementName=MeterCanvas}" ScaleY="{Binding ActualHeight, ElementName=MeterCanvas}" />
</PathGeometry.Transform>
<PathGeometry.Figures>
<PathFigure IsClosed ="True" StartPoint="{Binding Path=thePoints[0]}">
<PathFigure.Segments>
<PathSegmentCollection>
<PolyLineSegment Points="{Binding thePoints, UpdateSourceTrigger=PropertyChanged}" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
<Label Content="{Binding thePoints[0]}" Margin="14,58,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
<Label Content="{Binding thePoints[1]}" Margin="14,88,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
<Label Content="{Binding thePoints[2]}" Margin="165,58,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
<Label Content="{Binding thePoints[3]}" Margin="165,93,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
</Grid>
</Window>
主窗口:
public partial class MainWindow : Window
{
private MainViewModel mvm;
public MainWindow()
{
InitializeComponent();
mvm = new MainViewModel();
this.DataContext = mvm;
}
private void click_MouseDown(object sender, MouseButtonEventArgs e)
{
mvm.theText = mvm.theText + ".";
mvm.ChangePoint(.4);
}
}
模型视图:
class MainViewModel : INotifyPropertyChanged
{
private string _theText = "Initial";
private PointCollection _points = new PointCollection();
private PolyLineSegment segment;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
public MainViewModel()
{
ChangePoint(0.9);
}
public string theText
{
get { return _theText; }
set
{
if (_theText != value)
{
_theText = value;
OnPropertyChanged("theText");
}
}
}
public PointCollection thePoints
{
get
{ return _points; }
}
public void ChangePoint(double x)
{
_points.Clear();
AddPoint(new Point(0.2, 0.2));
AddPoint(new Point(0.2, 0.8));
AddPoint(new Point(x, 0.8));
AddPoint(new Point(x, 0.2));
OnPropertyChanged("thePoints");
_theText = _theText + "!";
OnPropertyChanged("theText");
}
public void AddPoint(Point p)
{
_points.Add(p);
}
}
感谢您的任何建议(工作:))
- 根据以下答案进行编辑 - 我添加了一个IValueConverter类:
public class PointCollectionConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.GetType() == typeof(ObservableCollection<Point>) && targetType == typeof(PointCollection))
{
var pointCollection = new PointCollection();
foreach (var point in value as ObservableCollection<Point>)
pointCollection.Add(point);
return pointCollection;
}
return null;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null; //not needed
}
#endregion
}
并将ModelView更改为使用Observable Collection ... 更新了ModelView:
class MainViewModel : INotifyPropertyChanged
{
private string _theText = "Initial";
private ObservableCollection<Point> _points;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
public MainViewModel()
{
_points = new ObservableCollection<Point>();
_points.Add(new Point(0.2, 0.2));
_points.Add(new Point(0.2, 0.8));
}
public string theText
{
get { return _theText; }
set
{
if (_theText != value)
{
_theText = value;
OnPropertyChanged("theText");
}
}
}
public ObservableCollection<Point> thePoints
{
get
{ return _points; }
}
double xAdder = 0;
double y = 0.0;
public void ChangePoint(double x)
{
y = y + .1;
if (y > .9) { y = .1; xAdder += .1; }
_points.Add(new Point(x+xAdder, y));
OnPropertyChanged("thePoints");
_theText = _theText + "!";
OnPropertyChanged("theText");
}
}
更新了XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ExampleGreg" x:Class="ExampleGreg.MainWindow"
Title="MainWindow" Height="161.614" Width="324.087">
<Window.Resources>
<local:PointCollectionConverter x:Key="pointCollectionConverter"/>
</Window.Resources>
<Grid x:Name="gridUser" MouseDown="click_MouseDown" >
<Canvas x:Name="MeterCanvas" Margin="14,7,30,0" Background="#FFAFAFAF" Height="35" VerticalAlignment="Top">
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry x:Name="geometry"/>
</Path.Data>
</Path>
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry x:Name="polylinePwr">
<PathGeometry.Transform>
<ScaleTransform ScaleX="{Binding ActualWidth, ElementName=MeterCanvas}" ScaleY="{Binding ActualHeight, ElementName=MeterCanvas}" />
</PathGeometry.Transform>
<PathGeometry.Figures>
<PathFigure StartPoint="{Binding Path=thePoints[0], Converter={StaticResource pointCollectionConverter}}">
<PathFigure.Segments>
<PathSegmentCollection>
<PolyLineSegment Points="{Binding thePoints, Converter={StaticResource pointCollectionConverter}}" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
<Label Content="{Binding thePoints[0]}" Margin="14,58,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
<Label Content="{Binding thePoints[1]}" Margin="14,88,199.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
<Label Content="{Binding thePoints[2]}" Margin="165,58,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
<Label Content="{Binding thePoints[3]}" Margin="165,93,29.6,0" VerticalAlignment="Top" Height="30" BorderThickness="1"/>
</Grid>
我不确定我是否会获得任何性能提升,因为IValueConverter创建了一个新的PointCollection每个ObservableCollection都被更改。
感谢大家帮助我完成这项工作。我希望将完整的代码粘贴为有效,如果有其他代码遇到同样的事情。
编辑#2 - 将Observable w / IValueConverter与复制PointCollection基准测试到新的PointCollection后,Point Collection看起来更快:
// Option 2 - WAY Faster.
// Just Use a Points Collection, copy it, and add a point.
public void AddPoint2(Point pt)
{
PointCollection pc = new PointCollection(_points2);
pc.Add(new Point(pt.X, pt.Y));
_points2 = pc;
OnPropertyChanged("thePoints2");
}
来自
// 5000 point sinwave for testing
foreach (Point pt in sinWave) mvm.AddPoint2(pt);
x++;
如果有更好的方式,评论表示赞赏。
答案 0 :(得分:1)
尝试替换属性,而不是清除+重新填充它。
public void ChangePoint(double x)
{
var newPoints = new PointCollection();
newPoints.Add(new Point(0.2, 0.2));
newPoints.Add(new Point(0.2, 0.8));
newPoints.Add(new Point(x, 0.8));
newPoints.Add(new Point(x, 0.2));
OnPropertyChanged("thePoints");
_theText = _theText + "!";
OnPropertyChanged("theText");
}
似乎绑定有时会忽略&#34; PropertyChanged&#34;如果对象引用相同,则为event。