【问题标题】:Why is the Binding of the Point3DCollection not working?为什么 Point3DCollection 的绑定不起作用?
【发布时间】:2019-04-23 15:16:29
【问题描述】:

你好,

我的 Point3DCollection 的生成工作正常,并且我在 Viewport3D (https://imgur.com/5Hzitw2) 中获得了网格,但是即使调用了我的 ViewModel 中的 OnPropertyChanged 方法,calculateNoise() 也不会更新我在 Viewport3D 中的绑定位置。我在这里做错了什么?

提前致谢, 康斯特IT

XAML:

<Viewport3D>
    <Viewport3D.Camera>
        <PerspectiveCamera x:Name="camera"/>
    </Viewport3D.Camera>
    <ModelVisual3D>
        <ModelVisual3D.Content>
            <Model3DGroup>
                <DirectionalLight Color="White" Direction="-1, -1, -3" />
                <GeometryModel3D>
                    <GeometryModel3D.Geometry>
                        <MeshGeometry3D Positions="{Binding Positions}" TriangleIndices="{Binding TriangleIndices}"/>
                    </GeometryModel3D.Geometry>
                    <GeometryModel3D.Material>
                        <DiffuseMaterial Brush="White"/>
                    </GeometryModel3D.Material>
                </GeometryModel3D>
            </Model3DGroup>
        </ModelVisual3D.Content>
    </ModelVisual3D>
</Viewport3D>

视口视图模型:

 internal class ViewportViewModel : INotifyPropertyChanged
 {
     private int _terrainSize;
     private Point3DCollection _positions;
     private Int32Collection _triangleIndices;
     private Random random = new Random();

     public Point3DCollection Positions
        {
            get
            {
                return _positions;
            }
            set
            {
                _positions = value;
                OnPropertyChanged("Positions");
            }
        }
     public Int32Collection TriangleIndices
        {
            get
            {
                return _triangleIndices;
            }
            set
            {
                _triangleIndices = value;
                OnPropertyChanged("TriangleIndices");
            }
        }

     public ViewportViewModel()
     {
         _terrainSize = 56;
         _positions = new Point3DCollection();
         _triangleIndices = new Int32Collection();
         GeneratePositions();
         GenerateTriangleIndices();
         CalculateNoiseCommand = new CalculateNoiseCommand(this);
     }

     private void GeneratePositions()
        { //Works }

     private void GenerateTriangleIndices()
        { //Works }

     //Handling
     ...

     internal void CalculateNoise()
     {
         for (int i = 0; i < _terrainSize * _terrainSize; i++)
         {
             Point3D point = new Point3D();
             point = Positions[i];
             point.Y = random.Next(10) / 10.0;
             Positions[i] = point;
         }
         OnPropertyChanged("Positions");
     }

     #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                Console.WriteLine("ViewportViewModel: " + propertyName);
            }
        }

        #endregion

 }

替换当前 Point3DCollection 的代码。它与在构造函数中调用的 GeneratePositions() 相同,只是在开头使用 Positions.Clear() 方法。它是通过CalculateNoise() 调用的。

        private void ReplacePositions()
        {
            if(Positions.Count > 0)
            {
                Positions.Clear();
            }

            var column = 0;
            var row = 0;
            Point3D point = new Point3D();

            for (int i = 0; i < _terrainSize * _terrainSize; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (j == 0)
                        point.X = ((float)column / ((float)_terrainSize - 1) - 0.5) * 2;
                    if (j == 1)
                        point.Y = 0;
                    if (j == 2)
                        point.Z = ((float)row / ((float)_terrainSize - 1) - 0.5) * 2;
                }

                Positions.Add(point);

                // Calculate next row & column
                column++;
                if (column % _terrainSize == 0)
                {
                    row++;
                }
                column %= _terrainSize;
            }
        }

        internal void CalculateNoise()
        {
            ReplacePositions();
            OnPropertyChanged("Positions");
        }

【问题讨论】:

  • 这个问题太宽泛了......请更具体一点,您在哪里尝试过什么?
  • 将 Point3DCollection 公开为实现 INotifyPropertyChanged 的​​视图模型的属性。我们称该属性为Points。在 XAML 中适当地绑定它。当您更改集合中的某个点时,调用 PropertyChanged(nameof(Points)) 以便绑定知道它需要更新目标属性。
  • 嘿@Ed Plunkett,感谢您的建议。不幸的是,这不起作用:( XAML 中的绑定:Positions="{Binding Points, UpdateSourceTrigger=PropertyChanged}" 和我在 viewModel 中调用的方法实际上调用了 INotifyPropertyChanged 接口的 OnPropertyChanged 方法。但不知何故,它不会更新绑定到 Viewport3D 的 Point3DCollection
  • 1) 在您阅读并理解其中的文档之前,请不要添加UpdateSourceTrigger=PropertyChanged。 2)请显示不起作用的代码。如果绑定完全有效,它应该是一个简单的修复。
  • 嘿@Ed Plunkett,我更改了通用问题并更新了代码。现在有 XAML 部分,我猜这很好,而 viewModel 出了问题。

标签: wpf mvvm data-binding


【解决方案1】:
public class GeometryTips : ViewModelBase
{
    #region " Private Fields "
    private int _terrainSize = 56;
    private Random random = new Random();
    #endregion

    #region " Public Properties "

    #region " MeshGeo "
    private MeshGeometry3D _MeshGeo;
    public MeshGeometry3D MeshGeo
    {
        get { return _MeshGeo; }
        set { this.Set(ref _MeshGeo, value); }
    }
    #endregion

    #endregion

    #region " Commands "

    #region " Create3DCommand "
    public RelayCommand Create3DCommand { get; private set; }
    private void Create3D()
    {
        for (int i = 0; i < _terrainSize * _terrainSize; i++)
        {
            Point3D point = new Point3D();
            point = MeshGeo.Positions[i];
            point.Y = random.Next(10) / 10.0;
            MeshGeo.Positions[i] = point;
        }
    }
    #endregion

    #endregion

    #region " Constructor "
    /// <summary>
    /// GeometryTips
    /// </summary>
    public GeometryTips()
    {
        this.Create3DCommand = new RelayCommand(Create3D);
        this._MeshGeo = new MeshGeometry3D();
        GeneratePositions();
        GenerateTriangleIndices();
    }
    #endregion

    #region " Private Functions "

    #region " GeneratePositions "
    /// <summary>
    /// GeneratePositions
    /// </summary>
    private void GeneratePositions()
    {

        var column = 0;
        var row = 0;
        Point3D point = new Point3D();

        for (int i = 0; i < _terrainSize * _terrainSize; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if (j == 0)
                    point.X = ((float)column / ((float)_terrainSize - 1) - 0.5) * 2;
                if (j == 1)
                    point.Y = 0;
                if (j == 2)
                    point.Z = ((float)row / ((float)_terrainSize - 1) - 0.5) * 2;
            }
            _MeshGeo.Positions.Add(point);

            // Calculate next row & column
            column++;
            if (column % _terrainSize == 0)
            {
                row++;
            }
            column %= _terrainSize;
        }
    }
    #endregion

    #region " GenerateTriangleIndices "
    /// <summary>
    /// GenerateTriangleIndices
    /// </summary>
    private void GenerateTriangleIndices()
    {
        var value = 0;

        for (int i = 0; i < _terrainSize * _terrainSize - _terrainSize; i++)
        {
            for (int triangle = 0; triangle < 3; triangle++)
            {
                if (i % _terrainSize == 0)
                {
                    break;
                }
                if (triangle == 0)
                {
                    value = i;
                }
                else if (triangle == 1)
                {
                    value = i + triangle + _terrainSize - 2;
                }
                else if (triangle == 2)
                {
                    value = i + triangle + _terrainSize - 2;
                }
                _MeshGeo.TriangleIndices.Add(value);
            }
            for (int triangle = 0; triangle < 3; triangle++)
            {
                if (i > 0 && ((i + 1) % _terrainSize) == 0)
                {
                    break;
                }
                if (triangle == 0)
                {
                    value = i + triangle;
                }
                else if (triangle == 1)
                {
                    value = i + triangle + _terrainSize - 1;
                }
                else if (triangle == 2)
                {
                    value = i + triangle - 1;
                }
                _MeshGeo.TriangleIndices.Add(value);
            }
        }
    }
    #endregion

    #endregion
}

我使用 MVVM Light 创建了这个视图模型。

我使用 MeshGeometry3D 类进行绑定。

这是我的 xaml:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="10"></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition Width="10"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="10"></RowDefinition>
        <RowDefinition></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="10"></RowDefinition>
    </Grid.RowDefinitions>
    <Viewport3D Grid.Column="1" Grid.Row="1">
        <Viewport3D.Camera>
            <PerspectiveCamera x:Name="camera"/>
        </Viewport3D.Camera>
        <ModelVisual3D>
            <ModelVisual3D.Content>
                <Model3DGroup>
                    <DirectionalLight Direction="-1, -1, -3"/>
                    <GeometryModel3D Geometry="{Binding MeshGeo}">
                        <GeometryModel3D.Material>
                            <DiffuseMaterial Brush="White"/>
                        </GeometryModel3D.Material>
                    </GeometryModel3D>
                </Model3DGroup>
            </ModelVisual3D.Content>
        </ModelVisual3D>
    </Viewport3D>
    <Button Grid.Column="1" Grid.Row="2" Content="Handle" Command="{Binding Create3DCommand}"></Button>
</Grid>

这对我有用,希望对您有所帮助...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 2013-05-05
    • 2014-10-20
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    相关资源
    最近更新 更多