WPF 使用 Helix 工具,PropertyChangedEventHandler 在尝试更新 ModelVisual3D 视图时始终为 null
WPF using Helix Tool, PropertyChangedEventHandler is always null while trying to update ModelVisual3D view
我是 WPF 的新手,我在尝试更新主 window UI 更改后遇到问题。
我有以下MainWindow.xaml(因为比较大,所以只展示一部分)
<Window
x:Class="SimpleDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
xmlns:local="clr-namespace:SimpleDemo"
Title="Plot 3D data"
Width="680"
Height="680" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
下一个重要部分是 MainWindow 的 3D 绘图部分,我在其中将绘图的内容与名为 Model 的 Model3D 对象绑定。
<!-- Remember to add light to the scene -->
<HelixToolkit:SunLight />
<!-- The content of this visual is defined in MainViewModel.cs -->
<ModelVisual3D Content="{Binding Path = Model, Mode=OneWayToSource,NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
<!-- You can also add elements here in the xaml -->
<HelixToolkit:GridLinesVisual3D
Width="800"
Length="800"
MajorDistance="15"
MinorDistance="15"
Thickness="0.05" />
</HelixToolkit:HelixViewport3D>
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
<Button Margin="5" Click="Backward_Click">Backward</Button>
<Button Margin="5" Click="Forward_Click">Forward</Button>
</StackPanel>
该程序的想法是从一个 txt 文件中读取前 500 个数据点 (x,y,z),然后使用 Helix Toolkit 从这些数据点创建一个 AddRectangularMesh()。我对多组点执行此操作,最终得到一个包含多个 AddRectangularMesh() 对象的网格。之后,我将最终结果显示到 HelixViewport3D。
在 UI 我有两个按钮前进和后退。前进按钮正在尝试从 txt 文件中绘制接下来的 500 个点。
在我的 MainWindow.xaml.cs 文件中,我调用了按钮的事件处理程序,这些按钮调用了 MainViewModel.cs 文件中的函数,其中计算了该数据点的所有函数,最终结果将是保存在Model3D模型对象上,然后必须绘制在UI.
按钮调用 Forward_click 事件并增加计数器以读取下一个数据点
<Button Margin="5" Click="Forward_Click">Forward</Button>
按下按钮后,事件处理程序被调用,但它为空,因此 UI 永远不会更新,我无法显示下一个数据点。
在我的代码中,我实现了事件处理程序,以监听模型的变化,因此在执行函数后,模型对象将被更新,然后调用处理程序来更新 UI.
MainViewModel Class 定义为:
public class MainViewModel : Window, INotifyPropertyChanged
事件处理程序如下:
private Model3D model;
public Model3D Model
{
get { return model; }
set
{
model = value;
OnPropertyChanged(nameof(Model));
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
我在代码上放置了断点,当我按下 Button 时,处理程序被调用但为空,然后没有任何更新或完成,该函数计算具有新点的新 Model3D 对象,但不绘制新结果。
如果我 运行 在 public MainViewModel()
部分显示相同的功能,则会显示前 500 个点,但由于 window 的第一个 运行。
这是模型对象在每次按下按钮后更新的方式。
public void CoreCalculations()
{
for (int i = 0 ; i < 500; i++)
{
//read File Line
// --- Do something with the points ---
// create a mesh using the points and AddRectangularMesh
}
MeshGeometry3D mesh = meshBuilder.ToMesh(true);
Material blueMaterial = MaterialHelper.CreateMaterial(Colors.Blue);
modelGroup.Children.Add(new GeometryModel3D { Geometry = mesh, Transform = new TranslateTransform3D(2, 0, 0), Material = blueMaterial, BackMaterial = blueMaterial });
Model = modelGroup;
}
尝试将 OneWayToSource
更改为 OneWay
。来自 documentation
Updates the source property when the target property changes.
你可能想反过来做。每当模型更改时更新目标。
MainViewModel
继承自 Window
有点奇怪。我建议看一下 helix3D“SimpleDemo”。只是为了确认更改模型有效,使 mainViewModel 继承 INotifyPropertyChanged,并添加以下代码:
private async Task RemoveModel()
{
await Task.Delay(5000);
Model = null;
OnPropertyChanged(nameof(Model));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
并在构造函数中调用RemoveModel
。这应该使模型在 5 秒后被删除。请注意,示例代码仅供调试使用,仅此而已。
您还应该能够使用 live visual tree explorer 来帮助调试 UI。
我是 WPF 的新手,我在尝试更新主 window UI 更改后遇到问题。
我有以下MainWindow.xaml(因为比较大,所以只展示一部分)
<Window
x:Class="SimpleDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
xmlns:local="clr-namespace:SimpleDemo"
Title="Plot 3D data"
Width="680"
Height="680" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
下一个重要部分是 MainWindow 的 3D 绘图部分,我在其中将绘图的内容与名为 Model 的 Model3D 对象绑定。
<!-- Remember to add light to the scene -->
<HelixToolkit:SunLight />
<!-- The content of this visual is defined in MainViewModel.cs -->
<ModelVisual3D Content="{Binding Path = Model, Mode=OneWayToSource,NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
<!-- You can also add elements here in the xaml -->
<HelixToolkit:GridLinesVisual3D
Width="800"
Length="800"
MajorDistance="15"
MinorDistance="15"
Thickness="0.05" />
</HelixToolkit:HelixViewport3D>
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
<Button Margin="5" Click="Backward_Click">Backward</Button>
<Button Margin="5" Click="Forward_Click">Forward</Button>
</StackPanel>
该程序的想法是从一个 txt 文件中读取前 500 个数据点 (x,y,z),然后使用 Helix Toolkit 从这些数据点创建一个 AddRectangularMesh()。我对多组点执行此操作,最终得到一个包含多个 AddRectangularMesh() 对象的网格。之后,我将最终结果显示到 HelixViewport3D。 在 UI 我有两个按钮前进和后退。前进按钮正在尝试从 txt 文件中绘制接下来的 500 个点。
在我的 MainWindow.xaml.cs 文件中,我调用了按钮的事件处理程序,这些按钮调用了 MainViewModel.cs 文件中的函数,其中计算了该数据点的所有函数,最终结果将是保存在Model3D模型对象上,然后必须绘制在UI.
按钮调用 Forward_click 事件并增加计数器以读取下一个数据点
<Button Margin="5" Click="Forward_Click">Forward</Button>
按下按钮后,事件处理程序被调用,但它为空,因此 UI 永远不会更新,我无法显示下一个数据点。 在我的代码中,我实现了事件处理程序,以监听模型的变化,因此在执行函数后,模型对象将被更新,然后调用处理程序来更新 UI.
MainViewModel Class 定义为:
public class MainViewModel : Window, INotifyPropertyChanged
事件处理程序如下:
private Model3D model;
public Model3D Model
{
get { return model; }
set
{
model = value;
OnPropertyChanged(nameof(Model));
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
我在代码上放置了断点,当我按下 Button 时,处理程序被调用但为空,然后没有任何更新或完成,该函数计算具有新点的新 Model3D 对象,但不绘制新结果。
如果我 运行 在 public MainViewModel()
部分显示相同的功能,则会显示前 500 个点,但由于 window 的第一个 运行。
这是模型对象在每次按下按钮后更新的方式。
public void CoreCalculations()
{
for (int i = 0 ; i < 500; i++)
{
//read File Line
// --- Do something with the points ---
// create a mesh using the points and AddRectangularMesh
}
MeshGeometry3D mesh = meshBuilder.ToMesh(true);
Material blueMaterial = MaterialHelper.CreateMaterial(Colors.Blue);
modelGroup.Children.Add(new GeometryModel3D { Geometry = mesh, Transform = new TranslateTransform3D(2, 0, 0), Material = blueMaterial, BackMaterial = blueMaterial });
Model = modelGroup;
}
尝试将 OneWayToSource
更改为 OneWay
。来自 documentation
Updates the source property when the target property changes.
你可能想反过来做。每当模型更改时更新目标。
MainViewModel
继承自 Window
有点奇怪。我建议看一下 helix3D“SimpleDemo”。只是为了确认更改模型有效,使 mainViewModel 继承 INotifyPropertyChanged,并添加以下代码:
private async Task RemoveModel()
{
await Task.Delay(5000);
Model = null;
OnPropertyChanged(nameof(Model));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
并在构造函数中调用RemoveModel
。这应该使模型在 5 秒后被删除。请注意,示例代码仅供调试使用,仅此而已。
您还应该能够使用 live visual tree explorer 来帮助调试 UI。