зеркало из https://github.com/DeGsoft/maui-linux.git
[Android] Fix previewer exceptions with shell (#5955)
* shell preivewer * nonappcompat hack * - moove up null check * internal IsDesignerContext
This commit is contained in:
Родитель
dbbc5d5413
Коммит
8a7ee8632e
|
@ -101,7 +101,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
var activity = (FormsAppCompatActivity)Context;
|
||||
var activity = (FormsAppCompatActivity)Context.GetActivity();
|
||||
|
||||
if (e.OldElement != null)
|
||||
((IPageController)e.OldElement).InternalChildren.CollectionChanged -= OnChildrenCollectionChanged;
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
|
||||
public bool MarkedForDispose { get; internal set; } = false;
|
||||
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = Context.GetFragmentManager());
|
||||
|
||||
protected override void OnLayout(bool changed, int l, int t, int r, int b)
|
||||
{
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
{
|
||||
if (_platform == null)
|
||||
{
|
||||
if (Context is FormsAppCompatActivity activity)
|
||||
if (Context.GetActivity() is FormsAppCompatActivity activity)
|
||||
{
|
||||
_platform = activity.Platform;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
}
|
||||
}
|
||||
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = Context.GetFragmentManager());
|
||||
|
||||
IPageController PageController => Element;
|
||||
|
||||
|
@ -745,7 +745,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
void SetupToolbar()
|
||||
{
|
||||
Context context = Context;
|
||||
var activity = (FormsAppCompatActivity)context;
|
||||
var activity = context.GetActivity();
|
||||
|
||||
AToolbar bar;
|
||||
if (FormsAppCompatActivity.ToolbarResource != 0)
|
||||
|
@ -935,7 +935,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
return;
|
||||
|
||||
Context context = Context;
|
||||
var activity = (FormsAppCompatActivity)context;
|
||||
AToolbar bar = _toolbar;
|
||||
ActionBarDrawerToggle toggle = _drawerToggle;
|
||||
|
||||
|
@ -954,8 +953,9 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
toggle.SyncState();
|
||||
}
|
||||
|
||||
if (NavigationPage.GetHasBackButton(currentPage))
|
||||
if (NavigationPage.GetHasBackButton(currentPage) && !Context.IsDesignerContext())
|
||||
{
|
||||
var activity = (global::Android.Support.V7.App.AppCompatActivity)context.GetActivity();
|
||||
var icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext);
|
||||
icon.Progress = 1;
|
||||
bar.NavigationIcon = icon;
|
||||
|
|
|
@ -369,8 +369,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
|
||||
void LayoutRootPage(Page page, int width, int height)
|
||||
{
|
||||
var activity = (FormsAppCompatActivity)_context;
|
||||
page.Layout(new Rectangle(0, 0, activity.FromPixels(width), activity.FromPixels(height)));
|
||||
page.Layout(new Rectangle(0, 0, _context.FromPixels(width), _context.FromPixels(height)));
|
||||
}
|
||||
|
||||
Task PresentModal(Page modal, bool animated)
|
||||
|
@ -457,9 +456,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
{
|
||||
if (changed)
|
||||
{
|
||||
var activity = (FormsAppCompatActivity)Context;
|
||||
|
||||
_modal.Layout(new Rectangle(0, 0, activity.FromPixels(r - l), activity.FromPixels(b - t)));
|
||||
_modal.Layout(new Rectangle(0, 0, Context.FromPixels(r - l), Context.FromPixels(b - t)));
|
||||
_backgroundView.Layout(0, 0, r - l, b - t);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
}
|
||||
}
|
||||
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = Context.GetFragmentManager());
|
||||
bool IsBottomTabPlacement => (Element != null) ? Element.OnThisPlatform().GetToolbarPlacement() == ToolbarPlacement.Bottom : false;
|
||||
|
||||
public Color BarItemColor
|
||||
|
@ -231,7 +231,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
var activity = (FormsAppCompatActivity)Context;
|
||||
var activity = Context.GetActivity();
|
||||
|
||||
if (e.OldElement != null)
|
||||
((IPageController)e.OldElement).InternalChildren.CollectionChanged -= OnChildrenCollectionChanged;
|
||||
|
|
|
@ -5,6 +5,7 @@ using Android.Util;
|
|||
using Android.Views.InputMethods;
|
||||
using AApplicationInfoFlags = Android.Content.PM.ApplicationInfoFlags;
|
||||
using AActivity = Android.App.Activity;
|
||||
using AFragmentManager = Android.Support.V4.App.FragmentManager;
|
||||
|
||||
namespace Xamarin.Forms.Platform.Android
|
||||
{
|
||||
|
@ -96,5 +97,49 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static Context GetThemedContext(this Context context)
|
||||
{
|
||||
if (context == null)
|
||||
return null;
|
||||
|
||||
if (context.IsDesignerContext())
|
||||
return context;
|
||||
|
||||
if (context is global::Android.Support.V7.App.AppCompatActivity activity)
|
||||
return activity.SupportActionBar.ThemedContext;
|
||||
|
||||
if (context is ContextWrapper contextWrapper)
|
||||
return contextWrapper.BaseContext.GetThemedContext();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static bool IsDesignerContext(this Context context)
|
||||
{
|
||||
if (context == null)
|
||||
return false;
|
||||
|
||||
if ($"{context.ToString()}".Contains("com.android.layoutlib.bridge.android.BridgeContext"))
|
||||
return true;
|
||||
|
||||
if (context is ContextWrapper contextWrapper)
|
||||
return contextWrapper.BaseContext.IsDesignerContext();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static AFragmentManager GetFragmentManager(this Context context)
|
||||
{
|
||||
if (context == null)
|
||||
return null;
|
||||
|
||||
var activity = context.GetActivity();
|
||||
|
||||
if (activity is global::Android.Support.V4.App.FragmentActivity fa)
|
||||
return fa.SupportFragmentManager;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
if (disposing)
|
||||
{
|
||||
_renderer.Dispose();
|
||||
_renderer?.Dispose();
|
||||
_renderer = null;
|
||||
_view = null;
|
||||
_context = null;
|
||||
|
|
|
@ -38,13 +38,48 @@ namespace Xamarin.Forms.Platform.Android
|
|||
protected virtual void LoadView(IShellContext shellContext)
|
||||
{
|
||||
var context = shellContext.AndroidContext;
|
||||
var coordinator = LayoutInflater.FromContext(context).Inflate(Resource.Layout.FlyoutContent, null);
|
||||
var recycler = coordinator.FindViewById<RecyclerView>(Resource.Id.flyoutcontent_recycler);
|
||||
var appBar = coordinator.FindViewById<AppBarLayout>(Resource.Id.flyoutcontent_appbar);
|
||||
var coordinator = (ViewGroup)LayoutInflater.FromContext(context).Inflate(Resource.Layout.FlyoutContent, null);
|
||||
var recycler = coordinator.FindViewById<RecyclerView>(Resource.Id.flyoutcontent_recycler);
|
||||
var appBar = coordinator.FindViewById<ViewGroup>(Resource.Id.flyoutcontent_appbar);
|
||||
|
||||
_rootView = coordinator;
|
||||
_rootView = coordinator;
|
||||
|
||||
appBar.AddOnOffsetChangedListener(this);
|
||||
if((recycler == null || appBar == null) && !context.IsDesignerContext())
|
||||
{
|
||||
if (recycler == null)
|
||||
throw new ArgumentNullException("flyoutcontent_recycler", "Unable to find layout for flyoutcontent_recycler");
|
||||
|
||||
// PREVIEWER HACK for some reason previewer pulls this out as a FrameLayout and ignores the internal resources
|
||||
if (appBar == null)
|
||||
throw new ArgumentNullException("flyoutcontent_appbar", "Unable to find layout for flyoutcontent_recycler");
|
||||
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// PREVIEWER HACK for some reason previewer can't find the resources for the recycler or the appBar
|
||||
if (recycler == null)
|
||||
recycler = (RecyclerView)coordinator.GetChildAt(1);
|
||||
if (appBar == null)
|
||||
appBar = (AppBarLayout)coordinator.GetChildAt(0);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// PReviewer hack.
|
||||
// appcompat and non appcompat initialize this whole thing differently so the above are for appcompat the below are for non
|
||||
}
|
||||
|
||||
// PREVIEWER HACK for some reason previewer can't find the resources for the recycler or the appBar
|
||||
if (recycler == null)
|
||||
recycler = coordinator.FindViewById<RecyclerView>(context.Resources.GetIdentifier("flyoutcontent_recycler", "id", context.PackageName));
|
||||
|
||||
// PREVIEWER HACK for some reason previewer pulls this out as a FrameLayout and ignores the internal resources
|
||||
if (appBar == null)
|
||||
appBar = coordinator.FindViewById<ViewGroup>(context.Resources.GetIdentifier("flyoutcontent_appbar", "id", context.PackageName));
|
||||
|
||||
|
||||
(appBar as AppBarLayout)?.AddOnOffsetChangedListener(this);
|
||||
|
||||
int actionBarHeight = (int)context.ToPixels(56);
|
||||
|
||||
|
@ -68,11 +103,14 @@ namespace Xamarin.Forms.Platform.Android
|
|||
var metrics = context.Resources.DisplayMetrics;
|
||||
var width = Math.Min(metrics.WidthPixels, metrics.HeightPixels);
|
||||
|
||||
TypedValue tv = new TypedValue();
|
||||
if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ActionBarSize, tv, true))
|
||||
{
|
||||
actionBarHeight = TypedValue.ComplexToDimensionPixelSize(tv.Data, metrics);
|
||||
}
|
||||
using (TypedValue tv = new TypedValue())
|
||||
{
|
||||
if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ActionBarSize, tv, true))
|
||||
{
|
||||
actionBarHeight = TypedValue.ComplexToDimensionPixelSize(tv.Data, metrics);
|
||||
}
|
||||
}
|
||||
|
||||
width -= actionBarHeight;
|
||||
|
||||
coordinator.LayoutParameters = new LP(width, LP.MatchParent);
|
||||
|
|
|
@ -36,7 +36,10 @@ namespace Xamarin.Forms.Platform.Android
|
|||
VisualElementTracker IVisualElementRenderer.Tracker => null;
|
||||
|
||||
AView IVisualElementRenderer.View => _flyoutRenderer.AndroidView;
|
||||
ViewGroup IVisualElementRenderer.ViewGroup => _flyoutRenderer.AndroidView as ViewGroup;
|
||||
|
||||
// Used by Previewer
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public ViewGroup ViewGroup => _flyoutRenderer.AndroidView as ViewGroup;
|
||||
|
||||
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
|
||||
{
|
||||
|
@ -59,7 +62,9 @@ namespace Xamarin.Forms.Platform.Android
|
|||
{
|
||||
}
|
||||
|
||||
void IVisualElementRenderer.UpdateLayout()
|
||||
// Used by Previewer
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void UpdateLayout()
|
||||
{
|
||||
var width = (int)AndroidContext.ToPixels(Element.Width);
|
||||
var height = (int)AndroidContext.ToPixels(Element.Height);
|
||||
|
@ -151,7 +156,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
protected Context AndroidContext { get; }
|
||||
protected Shell Element { get; private set; }
|
||||
private FragmentManager FragmentManager => ((FormsAppCompatActivity)AndroidContext).SupportFragmentManager;
|
||||
FragmentManager FragmentManager => AndroidContext.GetFragmentManager();
|
||||
|
||||
protected virtual IShellObservableFragment CreateFragmentForPage(Page page)
|
||||
{
|
||||
|
@ -202,9 +207,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == Shell.CurrentItemProperty.PropertyName)
|
||||
{
|
||||
SwitchFragment(FragmentManager, _frameLayout, Element.CurrentItem);
|
||||
}
|
||||
|
||||
_elementPropertyChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
@ -223,13 +226,18 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
((IShellController)shell).AddAppearanceObserver(this, shell);
|
||||
|
||||
SwitchFragment(FragmentManager, _frameLayout, shell.CurrentItem, false);
|
||||
// Previewer Hack
|
||||
if(AndroidContext.GetActivity() != null)
|
||||
SwitchFragment(FragmentManager, _frameLayout, shell.CurrentItem, false);
|
||||
}
|
||||
|
||||
IShellItemRenderer _currentRenderer;
|
||||
|
||||
protected virtual void SwitchFragment(FragmentManager manager, AView targetView, ShellItem newItem, bool animate = true)
|
||||
{
|
||||
if (AndroidContext.IsDesignerContext())
|
||||
return;
|
||||
|
||||
var previousRenderer = _currentRenderer;
|
||||
_currentRenderer = CreateShellItemRenderer(newItem);
|
||||
_currentRenderer.ShellItem = newItem;
|
||||
|
@ -266,10 +274,10 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
void UpdateStatusBarColor(ShellAppearance appearance)
|
||||
{
|
||||
var activity = ((FormsAppCompatActivity)AndroidContext);
|
||||
var window = activity.Window;
|
||||
var decorView = window.DecorView;
|
||||
var resources = activity.Resources;
|
||||
var activity = AndroidContext.GetActivity();
|
||||
var window = activity?.Window;
|
||||
var decorView = window?.DecorView;
|
||||
var resources = AndroidContext.Resources;
|
||||
|
||||
int statusBarHeight = 0;
|
||||
int resourceId = resources.GetIdentifier("status_bar_height", "dimen", "android");
|
||||
|
@ -285,19 +293,23 @@ namespace Xamarin.Forms.Platform.Android
|
|||
navigationBarHeight = resources.GetDimensionPixelSize(resourceId);
|
||||
}
|
||||
|
||||
// we are using the split drawable here to avoid GPU overdraw.
|
||||
// All it really is is a drawable that only draws under the statusbar/bottom bar to make sure
|
||||
// we dont draw over areas we dont need to. This has very limited benefits considering its
|
||||
// only saving us a flat color fill BUT it helps people not freak out about overdraw.
|
||||
if (appearance != null)
|
||||
// TODO Previewer Hack
|
||||
if (decorView != null)
|
||||
{
|
||||
var color = appearance.BackgroundColor.ToAndroid(Color.FromHex("#03A9F4"));
|
||||
decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
|
||||
}
|
||||
else
|
||||
{
|
||||
var color = Color.FromHex("#03A9F4").ToAndroid();
|
||||
decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
|
||||
// we are using the split drawable here to avoid GPU overdraw.
|
||||
// All it really is is a drawable that only draws under the statusbar/bottom bar to make sure
|
||||
// we dont draw over areas we dont need to. This has very limited benefits considering its
|
||||
// only saving us a flat color fill BUT it helps people not freak out about overdraw.
|
||||
if (appearance != null)
|
||||
{
|
||||
var color = appearance.BackgroundColor.ToAndroid(Color.FromHex("#03A9F4"));
|
||||
decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
|
||||
}
|
||||
else
|
||||
{
|
||||
var color = Color.FromHex("#03A9F4").ToAndroid();
|
||||
decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -236,23 +236,21 @@ namespace Xamarin.Forms.Platform.Android
|
|||
var backButtonHandler = Shell.GetBackButtonBehavior(page);
|
||||
toolbar.SetNavigationOnClickListener(this);
|
||||
|
||||
var activity = (FormsAppCompatActivity)context;
|
||||
|
||||
if (backButtonHandler != null)
|
||||
{
|
||||
await UpdateDrawerArrowFromBackButtonBehavior(context, toolbar, drawerLayout, backButtonHandler, activity);
|
||||
await UpdateDrawerArrowFromBackButtonBehavior(context, toolbar, drawerLayout, backButtonHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
await UpdateDrawerArrow(context, toolbar, drawerLayout, activity);
|
||||
await UpdateDrawerArrow(context, toolbar, drawerLayout);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual async Task UpdateDrawerArrow(Context context, Toolbar toolbar, DrawerLayout drawerLayout, FormsAppCompatActivity activity)
|
||||
protected virtual async Task UpdateDrawerArrow(Context context, Toolbar toolbar, DrawerLayout drawerLayout)
|
||||
{
|
||||
if (_drawerToggle == null)
|
||||
if (_drawerToggle == null && !context.IsDesignerContext())
|
||||
{
|
||||
_drawerToggle = new ActionBarDrawerToggle((Activity)context, drawerLayout, toolbar,
|
||||
_drawerToggle = new ActionBarDrawerToggle(context.GetActivity(), drawerLayout, toolbar,
|
||||
R.String.Ok, R.String.Ok)
|
||||
{
|
||||
ToolbarNavigationClickListener = this,
|
||||
|
@ -267,7 +265,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
if (CanNavigateBack)
|
||||
{
|
||||
_drawerToggle.DrawerIndicatorEnabled = false;
|
||||
using (var icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext))
|
||||
using (var icon = new DrawerArrowDrawable(context.GetThemedContext()))
|
||||
{
|
||||
icon.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
|
||||
icon.Progress = 1;
|
||||
|
@ -288,7 +286,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
_drawerToggle.SyncState();
|
||||
}
|
||||
|
||||
protected virtual async Task UpdateDrawerArrowFromBackButtonBehavior(Context context, Toolbar toolbar, DrawerLayout drawerLayout, BackButtonBehavior backButtonHandler, FormsAppCompatActivity activity)
|
||||
protected virtual async Task UpdateDrawerArrowFromBackButtonBehavior(Context context, Toolbar toolbar, DrawerLayout drawerLayout, BackButtonBehavior backButtonHandler)
|
||||
{
|
||||
var behavior = backButtonHandler;
|
||||
var command = behavior.Command;
|
||||
|
@ -307,7 +305,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
if (CanNavigateBack && icon == null)
|
||||
{
|
||||
icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext);
|
||||
icon = new DrawerArrowDrawable(context.GetThemedContext());
|
||||
(icon as DrawerArrowDrawable).Progress = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
>
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/flyoutcontent.appbar"
|
||||
android:id="@+id/flyoutcontent_appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/flyoutcontent.recycler"
|
||||
android:id="@+id/flyoutcontent_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Forms.Sandbox.ShellPage">
|
||||
|
||||
<ShellContent Title="test">
|
||||
<ContentPage></ContentPage>
|
||||
</ShellContent>
|
||||
</Shell>
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Forms.Sandbox
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class ShellPage : Shell
|
||||
{
|
||||
public ShellPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,12 @@
|
|||
<DebugType>pdbonly</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="ShellPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- A reference to the entire .NET Framework is automatically included -->
|
||||
|
|
Загрузка…
Ссылка в новой задаче