diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 38aba81cceaee2655ff49f547e2868976cf8982e..0e3eb86cb2ff31da0375657bb7e75cbc0e13f91c 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -366,6 +366,7 @@ Properties on Source Files
    /prop_sf/SKIP_AUTOUIC
    /prop_sf/SYMBOLIC
    /prop_sf/VS_COPY_TO_OUT_DIR
+   /prop_sf/VS_CSHARP_tagname
    /prop_sf/VS_DEPLOYMENT_CONTENT
    /prop_sf/VS_DEPLOYMENT_LOCATION
    /prop_sf/VS_INCLUDE_IN_VSIX
diff --git a/Help/prop_sf/VS_CSHARP_tagname.rst b/Help/prop_sf/VS_CSHARP_tagname.rst
new file mode 100644
index 0000000000000000000000000000000000000000..d42159f6daf77b68b552d8b718e7a9e70cdc653b
--- /dev/null
+++ b/Help/prop_sf/VS_CSHARP_tagname.rst
@@ -0,0 +1,19 @@
+VS_CSHARP_<tagname>
+-------------------
+
+Visual Studio and CSharp source-file-specific configuration.
+
+Tell the Visual Studio generator to set the source file tag
+``<tagname>`` to a given value in the generated Visual Studio CSharp
+project. Ignored on other generators and languages. This property
+can be used to define dependencies between source files or set any
+other Visual Studio specific parameters.
+
+Example usage:
+
+.. code-block:: cmake
+
+  set_source_files_property(<filename>
+           PROPERTIES
+           VS_CSHARP_DependentUpon <other file>
+           VS_CSHARP_SubType "Form")
diff --git a/Help/release/3.8.rst b/Help/release/3.8.rst
index d427a6377bf5eba988f5e72fbeb7ce845c04ca72..a9bfe84b28abec9d6b2356a947ce0482df775c8d 100644
--- a/Help/release/3.8.rst
+++ b/Help/release/3.8.rst
@@ -34,15 +34,6 @@ C#
   Visual Studio (``VS_*``) are worth a look (for setting toolset
   versions, root namespaces, assembly icons, ...).
 
-* Auto-linking in ``.csproj`` files: In C#/.NET development with
-  Visual Studio there are a number of visual editors used which
-  generate code.  Both the generated files and the ones edited
-  with the UI are connected in the ``.csproj`` file using
-  ``<DependentUpon>`` tags.  If CMake finds within a C# project
-  any source file with extension ``.Designer.cs`` or ``.xaml.cs``,
-  it checks sibling files with extension ``.xaml``, ``.settings``,
-  ``.resx`` or ``.cs`` and establishes the dependency connection.
-
 CUDA
 ^^^^
 
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index b193f65e17a1277d3ab3ccf3565094d883d9933d..bbcc3006b6ba164256573f05f356a603a9d261d0 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -86,6 +86,7 @@ public:
 
   // Get the properties
   cmPropertyMap& GetProperties() { return this->Properties; }
+  const cmPropertyMap& GetProperties() const { return this->Properties; }
 
   /**
    * Check whether the given source file location could refer to this
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 2e6c19bdec69fcbd5f8f64a6cbfcfe18b75f943c..1ac2951909a98850d3fc18e2cfe5aaa5fde5eb78 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -680,20 +680,40 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup()
           if (const char* g = (*oi)->GetProperty("VS_RESOURCE_GENERATOR")) {
             generator = g;
           }
-          this->WriteString("<Generator>", 3);
-          (*this->BuildFileStream) << cmVS10EscapeXML(generator)
-                                   << "</Generator>\n";
-          if (designerResource.find(srcDir) == 0) {
-            designerResource = designerResource.substr(srcDir.length() + 1);
-          } else if (designerResource.find(binDir) == 0) {
-            designerResource = designerResource.substr(binDir.length() + 1);
-          } else {
-            designerResource =
-              cmsys::SystemTools::GetFilenameName(designerResource);
+          if (!generator.empty()) {
+            this->WriteString("<Generator>", 3);
+            (*this->BuildFileStream) << cmVS10EscapeXML(generator)
+                                     << "</Generator>\n";
+            if (designerResource.find(srcDir) == 0) {
+              designerResource = designerResource.substr(srcDir.length() + 1);
+            } else if (designerResource.find(binDir) == 0) {
+              designerResource = designerResource.substr(binDir.length() + 1);
+            } else {
+              designerResource =
+                cmsys::SystemTools::GetFilenameName(designerResource);
+            }
+            this->ConvertToWindowsSlash(designerResource);
+            this->WriteString("<LastGenOutput>", 3);
+            (*this->BuildFileStream) << designerResource
+                                     << "</LastGenOutput>\n";
+          }
+        }
+        const cmPropertyMap& props = (*oi)->GetProperties();
+        for (cmPropertyMap::const_iterator p = props.begin(); p != props.end();
+             ++p) {
+          static const std::string propNamePrefix = "VS_CSHARP_";
+          if (p->first.find(propNamePrefix.c_str()) == 0) {
+            std::string tagName = p->first.substr(propNamePrefix.length());
+            if (!tagName.empty()) {
+              std::string value = props.GetPropertyValue(p->first);
+              if (!value.empty()) {
+                this->WriteString("<", 3);
+                (*this->BuildFileStream) << tagName << ">";
+                (*this->BuildFileStream) << cmVS10EscapeXML(value);
+                (*this->BuildFileStream) << "</" << tagName << ">\n";
+              }
+            }
           }
-          this->ConvertToWindowsSlash(designerResource);
-          this->WriteString("<LastGenOutput>", 3);
-          (*this->BuildFileStream) << designerResource << "</LastGenOutput>\n";
         }
       }
 
@@ -1940,42 +1960,21 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
         sourceFileTags["Link"] = link;
       }
     }
-    // check if file is a generated .Designer.cs or .xaml.cs file
-    // to add additional necessary tags
-    const std::string fileExtension =
-      cmsys::SystemTools::GetFilenameExtension(f);
-    if (fileExtension == ".Designer.cs" || fileExtension == ".xaml.cs") {
-      f = f.substr(0, f.length() - fileExtension.length());
-      if (sourceFileTags.find("Link") == sourceFileTags.end() &&
-          !this->InSourceBuild) {
-        // add link fallback
-        sourceFileTags["Link"] =
-          cmsys::SystemTools::GetFilenameName(f) + fileExtension;
-      }
-      std::vector<std::string> extensions;
-      extensions.push_back(".resx");
-      extensions.push_back(".settings");
-      extensions.push_back(".xaml");
-      extensions.push_back(".cs");
-      std::string dependencyExtension;
-      for (std::vector<std::string>::iterator i = extensions.begin();
-           i != extensions.end(); ++i) {
-        if (cmsys::SystemTools::FileExists(f + *i)) {
-          dependencyExtension = *i;
-          // There should never be more than one match. Otherwise
-          // one cannot tell on which match the file depends.
-          break;
+    const cmPropertyMap& props = sf.GetProperties();
+    for (cmPropertyMap::const_iterator p = props.begin(); p != props.end();
+         ++p) {
+      static const std::string propNamePrefix = "VS_CSHARP_";
+      if (p->first.find(propNamePrefix.c_str()) == 0) {
+        std::string tagName = p->first.substr(propNamePrefix.length());
+        if (!tagName.empty()) {
+          const std::string val = props.GetPropertyValue(p->first);
+          if (!val.empty()) {
+            sourceFileTags[tagName] = val;
+          } else {
+            sourceFileTags.erase(tagName);
+          }
         }
       }
-      if (dependencyExtension == ".resx") {
-        sourceFileTags["DesignTime"] = "True";
-        sourceFileTags["AutoGen"] = "True";
-      } else if (dependencyExtension == ".settings") {
-        sourceFileTags["DesignTimeSharedInput"] = "True";
-        sourceFileTags["AutoGen"] = "True";
-      }
-      sourceFileTags["DependentUpon"] =
-        cmsys::SystemTools::GetFilenameName(f) + dependencyExtension;
     }
     // write source file specific tags
     if (!sourceFileTags.empty()) {