Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
}

.table-attr-mark {
font-size: 90%;
font-size: 85%;
color: var(--bs-success);
}
2 changes: 1 addition & 1 deletion src/BootstrapBlazor.Server/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<XmlDocsToCopy Include="%(Reference.RelativeDir)BootstrapBlazor*.xml" />
</ItemGroup>
<Message Text="Copying XML docs to output path: $(OutputPath)" Importance="High" />
<Copy SourceFiles="@(XmlDocsToCopy)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" Condition="Exists('%(RootDir)%(Directory)%(Filename)%(Extension)')" />
<Copy SourceFiles="@(XmlDocsToCopy)" DestinationFolder="$(OutputPath)" />
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of SkipUnchangedFiles="true" and the Condition attribute from the Copy task may cause unnecessary file copying on every build, potentially slowing down build times. The original attributes were performance optimizations:

  • SkipUnchangedFiles="true" avoids copying files that haven't changed
  • The Condition prevents errors when files don't exist

Unless there's a specific reason these optimizations are causing issues (such as stale documentation not being updated), consider keeping them. If they must be removed to fix the issue mentioned in #7553, please add a comment explaining why.

Suggested change
<Copy SourceFiles="@(XmlDocsToCopy)" DestinationFolder="$(OutputPath)" />
<Copy SourceFiles="@(XmlDocsToCopy)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" Condition="Exists('%(RootDir)%(Directory)%(Filename)%(Extension)')" />

Copilot uses AI. Check for mistakes.
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ private static List<AttributeItem> GetAttributeCore(Type type)
{
if (xmlDoc == null) return null;

var memberName = $"P:{property.DeclaringType?.FullName}.{property.Name}";
var type = property.DeclaringType ?? property.PropertyType;
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback logic when property.DeclaringType is null appears incorrect. Using property.PropertyType as a fallback doesn't make semantic sense - the declaring type (which class the property is declared in) and the property type (the type of the value) are completely different concepts.

For XML documentation lookup, we need the type where the property is declared, not the type of the property's value. If DeclaringType is null, this would typically indicate a reflection issue, and falling back to PropertyType would likely result in looking up documentation in the wrong location.

Consider either:

  1. Removing the fallback to PropertyType if it's not a valid scenario
  2. If this is intended to handle a specific edge case, add a comment explaining when and why DeclaringType would be null and why PropertyType is the correct fallback
Suggested change
var type = property.DeclaringType ?? property.PropertyType;
// DeclaringType is required to build the correct XML documentation member name.
// If it is null, we cannot reliably locate the summary, so return null instead
// of falling back to PropertyType (which represents the value type, not the owner).
var type = property.DeclaringType;
if (type == null)
{
return null;
}

Copilot uses AI. Check for mistakes.
var typeName = type.FullName ?? $"BootstrapBlazor.Components.{type.Name}";
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback construction $"BootstrapBlazor.Components.{type.Name}" when type.FullName is null may not produce accurate member names for XML documentation lookup. This assumes all types without a FullName belong to the BootstrapBlazor.Components namespace, which may not always be true.

FullName can be null for generic type parameters and some special types. For generic types, you might want to handle them differently. Consider adding validation or a comment explaining which types are expected to have null FullName and why this fallback is appropriate for those specific cases.

Suggested change
var typeName = type.FullName ?? $"BootstrapBlazor.Components.{type.Name}";
var typeName = type.FullName;
// FullName can be null for generic type parameters and some special types.
// In such cases we skip XML documentation lookup instead of fabricating a namespace,
// as that may not produce an accurate member name.
if (string.IsNullOrEmpty(typeName))
{
return null;
}

Copilot uses AI. Check for mistakes.
var memberName = $"P:{typeName}.{property.Name}";
var summaryElement = FindSummaryElement(xmlDoc, memberName);
return summaryElement == null ? null : GetLocalizedSummary(summaryElement);
}
Expand Down
33 changes: 15 additions & 18 deletions src/BootstrapBlazor/Components/Display/DisplayBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ namespace BootstrapBlazor.Components;
public abstract class DisplayBase<TValue> : BootstrapModuleComponentBase
{
/// <summary>
/// <para lang="zh">是否显示 标签</para>
/// <para lang="zh">是否显示标签</para>
/// <para lang="en">Whether to Show Label</para>
/// </summary>
protected bool IsShowLabel { get; set; }

/// <summary>
/// <para lang="zh">获得 the <see cref="FieldIdentifier"/> for the bound value.</para>
/// <para lang="zh">获得绑定值的 <see cref="FieldIdentifier"/></para>
/// <para lang="en">Gets the <see cref="FieldIdentifier"/> for the bound value.</para>
/// </summary>
protected FieldIdentifier? FieldIdentifier { get; set; }
Expand All @@ -40,7 +40,7 @@ public abstract class DisplayBase<TValue> : BootstrapModuleComponentBase
protected Type? ValueType { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 the value of the input. This should be used with two-way binding.</para>
/// <para lang="zh">获得/设置 输入组件的值,支持双向绑定。</para>
/// <para lang="en">Gets or sets the value of the input. This should be used with two-way binding.</para>
/// </summary>
/// <example>
Expand All @@ -51,28 +51,28 @@ public abstract class DisplayBase<TValue> : BootstrapModuleComponentBase
public TValue? Value { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 a 回调 that updates the bound value.</para>
/// <para lang="zh">获得/设置 用于更新绑定值的回调。</para>
/// <para lang="en">Gets or sets a callback that updates the bound value.</para>
/// </summary>
[Parameter]
public EventCallback<TValue?> ValueChanged { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 an expression that identifies the bound value.</para>
/// <para lang="zh">获得/设置 标识绑定值的表达式。</para>
/// <para lang="en">Gets or sets an expression that identifies the bound value.</para>
/// </summary>
[Parameter]
public Expression<Func<TValue?>>? ValueExpression { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 是否显示前置标签 默认值为 null 为空时默认不显示标签</para>
/// <para lang="zh">获得/设置 是否显示前置标签默认值为 null,为空时不显示标签</para>
/// <para lang="en">Gets or sets Whether to Show Label. Default is null, not show label when null</para>
/// </summary>
[Parameter]
public bool? ShowLabel { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 是否显示 Tooltip 多用于文字过长导致裁减时使用 默认 null</para>
/// <para lang="zh">获得/设置 是否显示 Tooltip,多用于文字过长导致裁剪时使用,默认 null</para>
/// <para lang="en">Gets or sets Whether to Show Tooltip. Default is null</para>
/// </summary>
[Parameter]
Expand All @@ -93,29 +93,28 @@ public abstract class DisplayBase<TValue> : BootstrapModuleComponentBase
protected ValidateForm? ValidateForm { get; set; }

/// <summary>
/// <para lang="zh">获得 IShowLabel 实例</para>
/// <para lang="en">Get IShowLabel Instance</para>
/// <para lang="zh">获得 <see cref="IShowLabel"/> 实例</para>
/// <para lang="en">Get <see cref="IShowLabel"/> Instance</para>
/// </summary>
[CascadingParameter(Name = "EditorForm")]
protected IShowLabel? EditorForm { get; set; }

/// <summary>
/// <para lang="zh">获得 InputGroup 实例</para>
/// <para lang="en">Get InputGroup Instance</para>
/// <para lang="zh">获得 <see cref="BootstrapInputGroup"/> 实例</para>
/// <para lang="en">Get <see cref="BootstrapInputGroup"/> Instance</para>
/// </summary>
[CascadingParameter]
protected BootstrapInputGroup? InputGroup { get; set; }

/// <summary>
/// <para lang="zh">获得 IFilter 实例</para>
/// <para lang="en">Get IFilter Instance</para>
/// <para lang="zh">获得 <see cref="IFilter"/> 实例</para>
/// <para lang="en">Get <see cref="IFilter"/> Instance</para>
/// </summary>
[CascadingParameter]
protected IFilter? Filter { get; set; }

/// <summary>
/// <para lang="zh">SetParametersAsync 方法</para>
/// <para lang="en">SetParametersAsync Method</para>
/// <inheritdoc/>
/// </summary>
/// <param name="parameters"></param>
public override Task SetParametersAsync(ParameterView parameters)
Expand All @@ -135,8 +134,7 @@ public override Task SetParametersAsync(ParameterView parameters)
}

/// <summary>
/// <para lang="zh">OnParametersSet 方法</para>
/// <para lang="en">OnParametersSet Method</para>
/// <inheritdoc/>
/// </summary>
protected override void OnParametersSet()
{
Expand Down Expand Up @@ -185,7 +183,6 @@ protected override void OnParametersSet()
/// <para lang="en">Format Value to String Method</para>
/// </summary>
/// <param name="value">The value to format.</param>
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the <returns> tag from the XML documentation is inconsistent with standard C# documentation practices. Methods should document their return values, especially for public or protected virtual methods. The English comment "A string representation of the value" provided useful information about what the method returns.

Consider keeping the <returns> tag to maintain complete documentation.

Suggested change
/// <param name="value">The value to format.</param>
/// <param name="value">The value to format.</param>
/// <returns>
/// <para lang="zh">值的字符串表示形式。</para>
/// <para lang="en">A string representation of the value.</para>
/// </returns>

Copilot uses AI. Check for mistakes.
/// <returns>A string representation of the value.</returns>
protected virtual string? FormatValueAsString(TValue? value)
{
string? ret;
Expand Down
6 changes: 3 additions & 3 deletions src/BootstrapBlazor/Components/Validate/ValidateBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public abstract class ValidateBase<TValue> : DisplayBase<TValue>, IValidateCompo
protected string? ErrorMessage { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 数据合规样式</para>
/// <para lang="en">Gets or sets the validation CSS class</para>
/// <para lang="zh">获得 数据合规样式</para>
/// <para lang="en">Gets the validation CSS class</para>
/// </summary>
protected string? ValidCss => IsValid.HasValue ? GetValidString(IsValid.Value) : null;

Expand All @@ -62,7 +62,7 @@ public abstract class ValidateBase<TValue> : DisplayBase<TValue>, IValidateCompo
protected string? Disabled => IsDisabled ? "disabled" : null;

/// <summary>
/// <para lang="zh">是否显示 必填项标记</para>
/// <para lang="zh">获得/设置 是否显示 必填项标记</para>
/// <para lang="en">Gets or sets whether to display the required field marker</para>
/// </summary>
protected string? Required { get; set; }
Expand Down
Loading