c# - WPF C#从不同的UIElement实时更新折线点
问题描述
您好,我正在创建带有点(椭圆)的折线,用户点击点后鼠标移动将更新该折线,问题是点正在移动,这很好,但不会更新 ObservableCollection 的源
主窗口.xaml
<Window x:Class="sampleWPF.MainWindow" xmlns="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:sampleWPF" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" Background="Green" MouseRightButtonDown="MainWindow_OnMouseRightButtonDown_">
<Window.Resources>
<l:PointCollectionConverter x:Key="pointCollectionConverter" />
</Window.Resources>
<Grid>
<Canvas x:Name="Canvas" Background="Yellow" Width="300" Height="300" MouseMove="UIElement_OnMouseMove">
<Polyline x:Name="polyline" Stroke="Black" Width="300" Height="300" Points="{Binding PointCollection, Converter={StaticResource pointCollectionConverter}}" />
<ItemsControl ItemsSource="{Binding PointCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/> <Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="10" Height="10" Fill="Blue" MouseLeftButtonDown="UIElement_OnMouseLeftButtonDown" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</Grid>
一些解释: MainWindow_OnMouseRightButtonDown_ 停止选定的椭圆移动。
UIElement_OnMouseMove 在画布中移动椭圆
UIElement_OnMouseLeftButtonDown 选择将被移动的椭圆
主窗口.xaml.cs
public partial class MainWindow: INotifyPropertyChanged {
public MainWindow() {
InitializeComponent();
DataContext = this;
PointCollection.Add(new Point(0, 0));
PointCollection.Add(new Point(20, 20));
PointCollection.Add(new Point(30, 30));
PointCollection.Add(new Point(50, 50));
PointCollection.Add(new Point(80, 80));
PointCollection.Add(new Point(100, 100));
}
private ObservableCollection < Point > PointCollectionProperty {
get;
set;
} = new ObservableCollection < Point > ();
public ObservableCollection < Point > PointCollection {
get => PointCollectionProperty;
set {
PointCollectionProperty = value;
OnPropertyChanged(nameof(PointCollection));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string caller) {
PropertyChanged ? .Invoke(this, new PropertyChangedEventArgs(caller));
}
Point point;
private Point selectedPoint;
bool activated = false;
private Ellipse selectedEllipse;
private ContentPresenter selectedContentPresenter;
private void UIElement_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
if (sender is Ellipse es) {
Mouse.Capture(es);
selectedEllipse = es;
var parent = VisualTreeHelper.GetParent(selectedEllipse);
if (parent != null) {
selectedContentPresenter = parent as ContentPresenter;
}
point = Mouse.GetPosition(selectedContentPresenter);
if (PointCollection.Any(t => t.X == Canvas.GetLeft(selectedContentPresenter) && t.Y == Canvas.GetTop(selectedContentPresenter))) {
Debug.WriteLine("found");
selectedPoint = PointCollection.FirstOrDefault(t =>
t.X == Canvas.GetLeft(selectedContentPresenter) && t.Y == Canvas.GetTop(selectedContentPresenter));
} else {
selectedPoint = new Point();
Debug.WriteLine("not found");
}
activated = true;
}
}
private void UIElement_OnMouseMove(object sender, MouseEventArgs e) {
if (selectedContentPresenter != null) {
if (activated) {
double top = Canvas.GetTop(selectedContentPresenter) + Mouse.GetPosition(selectedContentPresenter).Y + point.Y;
double left = Canvas.GetLeft(selectedContentPresenter) + Mouse.GetPosition(selectedContentPresenter).X + point.X;
Canvas.SetTop(selectedContentPresenter, top);
Canvas.SetLeft(selectedContentPresenter, left);
selectedPoint.X = left;
selectedPoint.Y = top;
OnPropertyChanged(nameof(PointCollection));
}
}
}
private void MainWindow_OnMouseRightButtonDown_(object sender, MouseButtonEventArgs e) {
foreach(Point child in PointCollection) {
Debug.WriteLine(child.X + " " + child.Y);// shows original values from public MainWindow()
}
Mouse.Capture(null);
activated = false;
selectedEllipse = null;
selectedContentPresenter = null;
}
}
public class PointCollectionConverter: IValueConverter {
Debug.WriteLine("Called");
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;
}
}
因为椭圆确实移动但折线保持不变,所以我在这里缺少什么
编辑:添加 Debug.WriteLine 以显示其是否正常工作,但垃圾邮件调试但收集保持不变
解决方案
推荐阅读
- reactjs - 我们可以在 React Kendo Grid Wrapper 上添加虚拟滚动吗
- flask - 无法让 wtf-tinymce 与我的 Flask 应用程序一起使用
- julia - 在 Julia 中使用数组作为索引
- reactjs - 将初始日期和最终日期添加到范围选择器 Highstock
- javascript - 在单独的函数中使用来自两个句柄、jquery-ui 范围滑块的值
- php - 检查 WooCommerce 中是否仍然存在与订单项目相关的产品
- typescript - Typescript - 将包含与类型化数组一起使用时出现意外错误
- git - 如何使用 libgit2 提交到裸存储库中的特殊分支?
- c# - dotnet build 产生“错误 NU1403:软件包 Libuv.1.9.1 sha512 验证失败”
- cs-cart - 如何以 1 英镑的价格为产品 3 定价,或以 2 的价格为产品 3 定价?