This tutorial explains how you can add more handles to an existing handles provider.

Other customizations

You need to customize a handles provider for advanced use cases only. For other customization methods, see this article.

The sample_editing sample supports this tutorial. It’s available for C++ and C#.

See this article for more information about editing.

Step 1 - Add an extra handle to an existing IEditHandles

The best way to add an extra handle to a set of handles is to wrap an existing IEditHandles instance, and add the handle. In this tutorial, we use two classes for this:

  • EditHandlesWrapper: this IEditHandles implementation is a utility class that makes it easier to wrap other IEditHandles instances. You can use it to override the IEditHandles::getList method to add more handles. Any change in the delegate IEditHandles also causes the wrapper to call the configured observers.

  • CustomFeatureEditHandles: this class extends from EditHandlesWrapper, and adds a handle that lets you change a 'transparency' property of the edited Feature.

The following code shows how you can do this. You can find the full code in the sample.

Program (C++): Wrapping an IEditHandles
class CustomFeatureEditHandles final : public EditHandlesWrapper {
public:
  explicit CustomFeatureEditHandles(std::shared_ptr<ObservableFeature> feature,
                                    std::shared_ptr<IFeatureEditCallback> featureEditCallback,
                                    std::shared_ptr<IEditHandles> delegateHandles,
                                    const std::shared_ptr<FeatureEditContext>& context)
      : EditHandlesWrapper(std::move(delegateHandles)), _feature{std::move(feature)}, _featureEditCallback{std::move(featureEditCallback)} {
    // Create a handle that controls the transparency
    _transparencyHandle = createTransparencyHandle(context);
  }
  std::vector<std::shared_ptr<IEditHandle>> getList() const override {
    auto handles = EditHandlesWrapper::getList();
    if (_transparencyHandle) {
      handles.emplace_back(_transparencyHandle);
    }
    return handles;
  }

private:
  std::shared_ptr<PointEditHandle> createTransparencyHandle(const std::shared_ptr<FeatureEditContext>& context) {
    // Create a handle that changes the transparency when the handle is dragged
    return handle;
  }
};

C#

internal sealed class CustomFeatureEditHandles : EditHandlesWrapper
{
    private readonly ObservableFeature _feature; // The current feature
    private readonly IFeatureEditCallback _featureEditCallback; // Called by the transparency handle when changing the feature state
    private ObservablePolyline _polyline; // The current polyline. This is derived from _feature
    private IInvalidationCallback _featureInvalidateCallback; // Used to detect feature changes, so that the handle location can be updated
    private readonly PointEditHandle _transparencyHandle; // The handle used to edit the transparency

    public CustomFeatureEditHandles(ObservableFeature feature, IFeatureEditCallback featureEditCallback, IEditHandles delegateHandles, FeatureEditContext context) : base(delegateHandles)
    {
        _feature = feature;
        _featureEditCallback = featureEditCallback;
        // Create a handle that controls the transparency
        _transparencyHandle = CreateTransparencyHandle(context);
    }

    public override IList<IEditHandle> GetList()
    {
        var handles = base.GetList();
        if (_transparencyHandle == null) return handles;
        handles = new List<IEditHandle>(handles) {_transparencyHandle};
        return handles;
    }

    private PointEditHandle CreateTransparencyHandle(FeatureEditContext context)
    {
        // Create a handle that changes the transparency when the handle is dragged
        return handle;
    }
}

Step 2 - Create a handles provider

To make sure that our custom IEditHandles is used, we must provide it through an IFeatureHandlesProvider implementation. In this tutorial, we introduce the CustomFeatureHandlesProvider class for this purpose.

This class mainly delegates to an existing IFeatureHandlesProvider, and also creates a new CustomFeatureEditHandles instance when we call it.

Program (C++): Creating an IFeatureHandlesProvider
CustomFeatureHandlesProvider::CustomFeatureHandlesProvider() : _delegateHandlesProvider(std::make_shared<FeatureHandlesProvider>()) {
}

bool CustomFeatureHandlesProvider::canProvide(const std::shared_ptr<ObservableFeature>& feature, const std::shared_ptr<FeatureEditContext>& context) const {
  return _delegateHandlesProvider->canProvide(feature, context);
}

std::shared_ptr<IEditHandles> CustomFeatureHandlesProvider::provide(std::shared_ptr<ObservableFeature> feature,
                                                                    const std::shared_ptr<FeatureEditContext>& context,
                                                                    std::shared_ptr<IFeatureEditCallback> featureEditCallback) const {
  auto delegateHandles = _delegateHandlesProvider->provide(feature, context, featureEditCallback);
  return std::make_shared<CustomFeatureEditHandles>(std::move(feature), std::move(featureEditCallback), delegateHandles, context);
}

C#

public sealed class CustomFeatureHandlesProvider : IFeatureHandlesProvider
{
    private readonly IFeatureHandlesProvider _delegateHandlesProvider;

    public CustomFeatureHandlesProvider()
    {
        _delegateHandlesProvider = new FeatureHandlesProvider();
    }

    public bool CanProvide(ObservableFeature feature, FeatureEditContext context)
    {
        return _delegateHandlesProvider.CanProvide(feature, context);
    }

    public IEditHandles Provide(ObservableFeature feature, FeatureEditContext context, IFeatureEditCallback featureEditCallback)
    {
        var delegateHandles = _delegateHandlesProvider.Provide(feature, context, featureEditCallback);
        return new CustomFeatureEditHandles(feature, featureEditCallback, delegateHandles, context);
    }
}

Step 3 - Use the custom feature handles provider

We need to make sure that the editing framework uses our custom handles provider, so we must configure it in an IFeatureEditConfiguration, and set that configuration on the FeatureLayer.

Program (C++): Creating an IFeatureHandlesProvider
// Use a custom edit configuration that changes the editing behavior for this layer
auto customEditConfiguration = std::make_shared<CustomEditConfiguration>();

// Register the configuration. This makes the layer editable by default
return FeatureLayer::newBuilder()
    .model(model) //
    .title("Tutorial 2")
    .editConfiguration(customEditConfiguration)
    .painter(std::make_shared<TransparencyFeaturePainter>())
    .build();

C#

// Use a custom edit configuration that changes the editing behavior for this layer
var customEditConfiguration = new CustomEditConfiguration();

// Register the configuration. This makes the layer editable by default
return FeatureLayer.NewBuilder()
    .Model(model)
    .Title("Tutorial 2")
    .EditConfiguration(customEditConfiguration)
    .Painter(new TransparencyFeaturePainter())
    .Build();