helix-toolkit / helix-toolkit

Helix Toolkit is a collection of 3D components for .NET.
http://helix-toolkit.org/
MIT License
1.89k stars 671 forks source link

Attached property to show/hide Visual3Ds #32

Open objorke opened 10 years ago

objorke commented 10 years ago

This issue was imported from CodePlex

objo wrote 2013-09-29 at 09:31 Add an attached property to show/hide Visual3Ds and Model3Ds

When hiding:

ModelVisual3D

ContainerUIElement3D

ModelUIElement3D

remove from the parent's Children collection

Model3D

if parent is a ModelVisual3D - remove it from parent's Content

if parent is a Model3DGroup - remove it from parent's Children

When removing from collections - add an empty placeholder in the collection (and make it thread safe)

Store old parents and placeholders in temporary attached properties

https://helixtoolkit.codeplex.com/workitem/10000

survivorx wrote 2013-09-29 at 11:34 I'll contribute this.

For GeometryModel3D we need a different solution using a dictionary because it's not a DependencyObject.

survivorx wrote 2013-09-29 at 12:46 Ok, after really looking at this I must admit I wrongly assumed Visual3D or ModelVisual3D had a Material property, but it's a property of BillboardVisual3D (and probably other Helix classes). So there is no easy general solution using Material.

A better solution might be disconnecting the Content from the Visual3D. This would affect the properties Visual3D.Visual3DModel (protected, reflection needed), ModelVisual3D.Children and ModelVisual3D.Content.

survivorx wrote 2013-09-30 at 17:15 Here is a solution for ModelGeometry3D using Material:

namespace Common
{
  using System.Windows;
  using System.Windows.Media.Media3D;

  public class Visibility3D : DependencyObject
  {
    public static readonly DependencyProperty IsHiddenProperty =
      DependencyProperty.RegisterAttached(
        "IsHidden", typeof(bool), typeof(Visibility3D), new PropertyMetadata(false, IsHiddenChangedCallback));

    private static readonly DependencyProperty HiddenMaterialProperty =
      DependencyProperty.RegisterAttached(
        "HiddenMaterial", typeof(Material), typeof(Visibility3D), new UIPropertyMetadata(null));

    private static readonly DependencyProperty HiddenBackMaterialProperty =
      DependencyProperty.RegisterAttached(
        "HiddenBackMaterial", typeof(Material), typeof(Visibility3D), new UIPropertyMetadata(null));

    static Visibility3D()
    {
      GeometryModel3D.MaterialProperty.OverrideMetadata(typeof(Visibility3D), new PropertyMetadata(null, null, CoerceMaterialCallback));
      GeometryModel3D.BackMaterialProperty.OverrideMetadata(typeof(Visibility3D), new PropertyMetadata(null, null, CoerceBackMaterialCallback));
    }

    public static bool GetIsHidden(DependencyObject d)
    {
      return (bool)d.GetValue(IsHiddenProperty);
    }

    public static void SetIsHidden(DependencyObject d, bool value)
    {
      d.SetValue(IsHiddenProperty, value);
    }

    private static void IsHiddenChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      var geom = (GeometryModel3D)d;
      if ((bool)e.NewValue)
      {
        geom.SetValue(HiddenMaterialProperty, geom.Material);
        geom.SetValue(HiddenBackMaterialProperty, geom.BackMaterial);
        geom.Material = null;
        geom.BackMaterial = null;
      }
      else
      {
        geom.Material = (Material)geom.GetValue(HiddenMaterialProperty);
        geom.BackMaterial = (Material)geom.GetValue(HiddenBackMaterialProperty);
        geom.ClearValue(HiddenMaterialProperty);
        geom.ClearValue(HiddenBackMaterialProperty);
      }
    }

    private static object CoerceMaterialCallback(DependencyObject d, object baseValue)
    {
      var geom = (GeometryModel3D)d;
      if ((bool)geom.GetValue(IsHiddenProperty))
      {
        d.SetValue(HiddenMaterialProperty, baseValue);
        return null;
      }

      return baseValue;
    }

    private static object CoerceBackMaterialCallback(DependencyObject d, object baseValue)
    {
      var geom = (GeometryModel3D)d;
      if ((bool)geom.GetValue(IsHiddenProperty))
      {
        d.SetValue(HiddenBackMaterialProperty, baseValue);
        return null;
      }

      return baseValue;
    }
  }
}

You can bind it to a ToggleButton like this:

mwpowellhtx commented 9 years ago

Where does this issue stand?

objorke commented 9 years ago

I think the proposed solution disconnecting the visuals is better than changing the material.

I am not sure if @survivorx is still working on this, so I have marked the issue "you(anyone) take it"!

mwpowellhtx commented 9 years ago

+1 for Attached Properties.