التواصل بين المكوّنات وDI
مرّروا البيانات بين المكوّنات الأبناء والآباء، واستخدموا المعلمات المتسلسلة، واحنوا الخدمات داخل المكوّنات.
التواصل بين المكوّنات وDI درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.
أنماط التواصل بين المكوّنات
تتواصل مكوّنات Blazor في ثلاثة اتجاهات: من الأصل إلى الابن (المعلمات)، ومن الابن إلى الأصل (EventCallback)، وعبر شجرة المكوّنات (CascadingParameters أو الخدمات المشتركة عبر DI).
من الأصل إلى الابن: المعلمات
أضف السمة [Parameter] إلى خاصية المكوّن لجعلها قابلة للتعيين من المكوّن الأصل. يمرّر المكوّن الأصل القيم كسمات HTML في وسم المكوّن.
@* Child: Alert.razor *@
<div class="alert alert-@Type">
@Message
</div>
@code {
[Parameter] public string Type { get; set; } = "info"; // primary, warning, danger
[Parameter, EditorRequired] public string Message { get; set; } = "";
}
@* Parent usage: *@
<Alert Type="danger" Message="Something went wrong!" />
<Alert Message="Record saved." />من الابن إلى الأصل: EventCallback
يعرّض المكوّن الابن معلمة من النوع EventCallback. ويوفّر المكوّن الأصل أسلوب معالج. يستدعي المكوّن الابن هذا المعالج عند وقوع حدث ما.
@* Child: QuantityPicker.razor *@
<button @onclick="() => OnChanged.InvokeAsync(Value - 1)">-</button>
<span>@Value</span>
<button @onclick="() => OnChanged.InvokeAsync(Value + 1)">+</button>
@code {
[Parameter] public int Value { get; set; } = 1;
[Parameter] public EventCallback<int> OnChanged { get; set; }
}
@* Parent: *@
<QuantityPicker Value="@_qty" OnChanged="q => _qty = q" />
<p>Quantity: @_qty</p>تواصل المكوّنات الشقيقة عبر الأصل
لكي تتواصل المكوّنات الشقيقة، مرّر البيانات عبر المكوّن الأصل المشترك. يحتفظ المكوّن الأصل بالحالة المشتركة ويمرّرها إلى المكوّنات الأبناء كمعلمات.
@* Parent holds shared state *@
<CategoryFilter OnChanged="c => _category = c" />
<ProductList Category="_category" />
@code {
private string _category = "All";
}
@* CategoryFilter raises an event -> Parent updates _category
-> ProductList re-renders with new Category *@المعلمات المتسلسلة
غلّف شجرة فرعية داخل <CascadingValue> لتمرير البيانات إلى جميع العناصر المنحدرة منها دون تمريرها عبر كل مكوّن وسيط.
@* Wrap a subtree *@
<CascadingValue Value="_theme">
<MainLayout />
</CascadingValue>
@code { private Theme _theme = new Theme { PrimaryColor = "#6366f1" }; }
@* Any descendant can receive it: *@
@code {
[CascadingParameter]
public Theme AppTheme { get; set; } = default!;
}
<h1 style="color: @AppTheme.PrimaryColor">Hello</h1>حقن الخدمات باستخدام @inject
استخدم التوجيه @inject لحقن خدمات DI المسجّلة مباشرةً في المكوّنات. يحلّ الإطار هذه الخدمات تلقائيًا.
@inject IProductService ProductSvc
@inject ILogger<ProductList> Logger
@inject NavigationManager Nav
@code {
private List<Product> _products = new();
protected override async Task OnInitializedAsync()
{
Logger.LogInformation("Loading products");
_products = await ProductSvc.GetAllAsync();
}
private void GoToProduct(int id)
=> Nav.NavigateTo($"/products/{id}");
}الخدمات ذات النطاق المحدد في Blazor Server
في Blazor Server، يستمر نطاق DI طوال مدة اتصال SignalR بالكامل — وليس لطلب واحد فقط. انتبه إلى أن الخدمات ذات النطاق المحدد تكون مشتركة بين جميع المكوّنات في الدائرة.
// Blazor Server: scoped = per circuit (connection lifetime)
builder.Services.AddScoped<CartService>();
// All components in the same browser tab share the SAME CartService
// This is GOOD for cart state (user's items persist across pages)
// This is BAD for request-scoped data — treat as session-like scope
// For true per-render-cycle scope, create your own:
using var scope = ScopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();NavigationManager للتوجيه
احقن NavigationManager للتنقل برمجيًا، وقراءة عنوان URL الحالي، ومعالجة أحداث التنقل.
@inject NavigationManager Nav
@code {
private void GoHome() => Nav.NavigateTo("/");
private void GoToProduct(int id) => Nav.NavigateTo($"/products/{id}");
private void ForceReload() => Nav.NavigateTo("/", forceLoad: true);
protected override void OnInitialized()
{
// Read current URL
var uri = Nav.Uri;
var path = new Uri(uri).AbsolutePath;
}
}HttpClient في Blazor WASM
في Blazor WebAssembly، احقن HttpClient مُعدًّا مسبقًا لاستدعاء واجهة API الخاصة بك. سجّله باستخدام عنوان أساسي في Program.cs.
// Program.cs (Blazor WASM)
builder.Services.AddScoped(sp => new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
// Component:
@inject HttpClient Http
@code {
private List<Product> _products = new();
protected override async Task OnInitializedAsync()
{
_products = await Http.GetFromJsonAsync<List<Product>>("/api/products")
?? new();
}
}من الواقع العملي: خدمة سياق المستخدم
تُحقن UserContextService ذات النطاق المحدد في عدة مكوّنات عبر التطبيق — ويرى كل مكوّن بيانات المستخدم نفسها دون تمرير الخصائص عبر سلسلة طويلة من المكوّنات.
public class UserContextService
{
public string? Name { get; private set; }
public bool IsAdmin { get; private set; }
public async Task InitializeAsync(AuthenticationState auth)
{
var user = auth.User;
Name = user.Identity?.Name;
IsAdmin = user.IsInRole("Admin");
}
}
// Registered as scoped:
builder.Services.AddScoped<UserContextService>();
// Used in any component:
@inject UserContextService UserCtx
<p>Hello, @UserCtx.Name @(UserCtx.IsAdmin ? "(Admin)" : "")</p>تحقق سريع
في Blazor Server، ما مدة حياة خدمة DI ذات النطاق المحدد؟
مراجعة: التواصل بين المكوّنات وDI
أهم النقاط:
- من الأصل إلى الابن: خصائص [Parameter]؛ استخدم [EditorRequired] للمعلمات الإلزامية
- من الابن إلى الأصل: EventCallback؛ يؤدي تلقائيًا إلى تشغيل StateHasChanged في المكوّن الأصل
- المكوّنات الشقيقة: مرّر البيانات عبر حالة المكوّن الأصل أو استخدم خدمة DI مشتركة
- عبر شجرة المكوّنات: استخدم CascadingValue/CascadingParameter مع الأشجار الفرعية العميقة
- استخدم @inject للخدمات؛ وتستمر الخدمات ذات النطاق المحدد في Blazor Server طوال مدة حياة الدائرة
- استخدم NavigationManager للتوجيه البرمجي
تعلم C# مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 93
- الدروس
- 346
الأسئلة الشائعة
هل درس «التواصل بين المكوّنات وDI» مجاني؟
نعم — نص درس «التواصل بين المكوّنات وDI» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.
ماذا ستتعلم في «التواصل بين المكوّنات وDI»؟
مرّروا البيانات بين المكوّنات الأبناء والآباء، واستخدموا المعلمات المتسلسلة، واحنوا الخدمات داخل المكوّنات. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «التواصل بين المكوّنات وDI»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- نموذج مكوّنات Blazor
- ربط البيانات ومعالجة الأحداث
- التواصل بين المكوّنات وDI
- إدارة الحالة في Blazor