Как преобразовать старый модуль визуализации Xamarin.Forms, полученный из IVisualElementRenderer, с помощью специальногоC#

Место общения программистов C#
Ответить
Anonymous
 Как преобразовать старый модуль визуализации Xamarin.Forms, полученный из IVisualElementRenderer, с помощью специального

Сообщение Anonymous »

У меня возникла серьезная проблема с преобразованием средств визуализации Xamarin.Forms в обработчики .NET MAUI.
Использование регистрации с помощью .AddCompatibilityRenderer не является вариантом, поскольку отображается только пустая страница (хорошо известно, что средства визуализации совместимости, ориентированные на всю страницу, непригодны, поскольку они не работа). Кроме того, мой модуль визуализации основан на интерфейсе IVisualElementRenderer и пользовательском контроллере, который добавляет определенные функции. Этот интерфейс позволяет экспортировать класс в качестве средства визуализации и использовать его в Xamarin.Forms. Однако я не нашел эквивалентного интерфейса в .NET MAUI. Я думал об использовании IViewHandler, но это кажется слишком сложным, потому что по сравнению с XF нужно реализовать гораздо больше, и это распространяется вокруг ViewHandler через несколько уровней наследования в MAUI. Это большая проблема, поскольку мое приложение использует довольно много таких средств визуализации, поэтому мне нужен универсальный способ их преобразования.
В качестве примера приведем StreamListPageRenderer, который служит для правильного отображения страницы на iOS. Он наследует от CancellationTokenViewController и отображает StreamListNativePage, который является собственной страницей, которая должна отображаться в iOS — это представление этого контроллера. Кроме того, средство визуализации реализует интерфейс IVisualElementRenderer.
StreamListPageRenderer

Код: Выделить всё

class StreamListPageRenderer : CancellationTokenViewController, IVisualElementRenderer
{
private ViewSources.StreamViewSource tableViewSource;
private bool disposed;

public async override void ViewDidLoad()
{
base.ViewDidLoad();
this.ProgressColor = UIColor.Black;
this.tableViewSource = new ViewSources.StreamViewSource(this.mainView.TableView);
this.mainView.TableView.Source = this.tableViewSource;
this.ViewModel.PropertyChanged += this.ViewModel_PropertyChanged;
if (this.Page != null)
{
await this.Page.OnPageLoaded();
}
}

public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
//We need to subscribe to the event in ViewDidLoad, but if disappearing is called, we need to re-subscribe it here.
//This ensures it won’t be subscribed twice.
this.ViewModel.PropertyChanged -= this.ViewModel_PropertyChanged;
this.ViewModel.PropertyChanged += this.ViewModel_PropertyChanged;
this.tableViewSource.ItemTouch += this.TableViewSource_ItemTouch;
this.tableViewSource.SetData(this.ViewModel.Items, this.mainView.TableView);
this.mainView.RefreshControl.ValueChanged += this.RefreshControl_ValueChanged;
}

private async void RefreshControl_ValueChanged(object sender, EventArgs e)
{
await this.ViewModel.RefreshData(true);
this.mainView.RefreshControl.EndRefreshing();
}

private void TableViewSource_ItemTouch(object sender, ViewModels.ItemViewModels.StreamItemViewModel e)
{
this.ViewModel.SelectedItem = e;
}

private void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(this.ViewModel.IsInBackgroundWorking))
{
this.SetBackgroundWorking(this.ViewModel.IsInBackgroundWorking, this.ViewModel.LoadingText);
}
else if (e.PropertyName == nameof(this.ViewModel.LoadingText))
{
this.SetBackgroundWorking(this.ViewModel.IsInBackgroundWorking, this.ViewModel.LoadingText);
}
else if (e.PropertyName == nameof(this.ViewModel.Items))
{
this.tableViewSource.SetData(this.ViewModel.Items, this.mainView.TableView);
}
}

public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
this.UnsubscribeEvents();
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
this.disposed = true;
this.UnsubscribeEvents();
}

protected override UIView RootView
{
get
{
if (!this.disposed)
return base.RootView;
return null;
}
}

private void UnsubscribeEvents()
{
this.ViewModel.PropertyChanged -= this.ViewModel_PropertyChanged;
this.tableViewSource.ItemTouch -= this.TableViewSource_ItemTouch;
this.mainView.RefreshControl.ValueChanged -= this.RefreshControl_ValueChanged;
}

public StreamListPage Page { get; private set; }
public StreamListViewModel ViewModel => (this.Page.BindingContext as StreamListViewModel);

#region Elements added for Xamarin.Forms compatibility (implementing IVisualElementRenderer)

public event EventHandler ElementChanged;
public VisualElement Element { get; private set; }
public UIView NativeView => this.View;
public UIViewController ViewController => this;
public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) => NativeView.GetSizeRequest(widthConstraint, heightConstraint);
public void SetElementSize(Size size) =>  Element.Layout(new Rect(Element.X, Element.Y, size.Width, size.Height));

public void SetElement(VisualElement element)
{
VisualElement oldElement = Element;
Element = element;
Page = (this.Element as StreamListPage);
UpdateTitle();
this.ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(oldElement, element));
}

private void UpdateTitle()
{
if (!string.IsNullOrWhiteSpace((this.Element as Page)?.Title))
NavigationItem.Title = (this.Element as Page).Title;
}

#endregion
}
CancellationTokenViewController
  • Этот контроллер наследуется от BackgroundWorkingViewController , который отвечает за отображение макетов загрузки и правильную загрузку индикаторов.

Код: Выделить всё

public class CancellationTokenViewController : BackgroundWorking.BackgroundWorkingViewController where T : UIView
{
private CancellationTokenSource cancelTokenSource;
private Task loadingTask;
private bool loadingTaskWasCanceled;

public async override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
await this.CheckAndRefreshCanceledOperations();
}

public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
this.Cancel();
}

protected async Task LoadData()
{
this.loadingTaskWasCanceled = false;
this.loadingTask = this.LoadData();
return await loadingTask;
}

protected virtual Task LoadDataInternal() => Task.FromResult(true);

/// 
/// Allows cancellation of the operation
/// 
protected CancellationToken CancelToken
{
get
{
if (this.cancelTokenSource == null)
this.InitCancelTokenSource();
return this.cancelTokenSource.Token;
}
}

/// 
/// Cancels the operation
/// 
private void Cancel()
{
ErrorLog.Instance.StartAddRecord(ErrorTypes.MESSAGE, $"this.cancelTokenSource != null = {this.cancelTokenSource != null}", "CancellationViewModel.Cancel() called");
if (this.cancelTokenSource != null && !this.cancelTokenSource.IsCancellationRequested && this.cancelTokenSource.Token.CanBeCanceled)
{
if (loadingTask != null &&  !loadingTask.IsCompleted)
loadingTaskWasCanceled = true;

this.cancelTokenSource.Cancel();
this.cancelTokenSource = null;
}
}

/// 
/// Checks if the previous loading operation was canceled, and if so, restarts it
/// 
/// 
private async Task CheckAndRefreshCanceledOperations()
{
ErrorLog.Instance.StartAddRecord(ErrorTypes.MESSAGE, $"loadingTaskWasCanceled-{loadingTaskWasCanceled}", "CheckAndRefreshCanceledOperations() called");
if (loadingTaskWasCanceled)
{
this.ResetCancelationTokenSource();
await this.LoadData();
}
}

/// 
/// Initializes a new Token
/// 
private void InitCancelTokenSource()
{
ErrorLog.Instance.StartAddRecord(ErrorTypes.MESSAGE, "CancellationViewModel.InitCancelTokenSource() called");
this.cancelTokenSource = new CancellationTokenSource();
}

/// 
/// Resets the token so the operation can no longer be stopped
/// 
private void ResetCancelationTokenSource()
{
this.cancelTokenSource = null;
}
}
StreamListNativePage

Код: Выделить всё

class StreamListNativePage : UIView
{
public StreamListNativePage()
{
this.TableView = this.CreateTableView();
}

private TableView CreateTableView()
{
var tableView = new TableView();
this.RefreshControl = new UIRefreshControl();
tableView.RefreshControl = this.RefreshControl;
tableView.SeparatorStyle = UITableViewCellSeparatorStyle.None;
tableView.AutoRowHeight = true;
tableView.EmptyText = "StreamList_EmptyText".LocalizeResx();
tableView.EmptyLabelsColor = ((Color)App.Current.Resources["PrimaryBackgroundTextColor"]).ToUIColor();
this.AddSubview(tableView);
tableView.LeadingAnchor.ConstraintEqualTo(this.LeadingAnchor, 0).Active = true;
tableView.TopAnchor.ConstraintEqualTo(this.TopAnchor, 0).Active = true;
tableView.TrailingAnchor.ConstraintEqualTo(this.TrailingAnchor, 0).Active = true;
tableView.BottomAnchor.ConstraintEqualTo(this.BottomAnchor, 0).Active = true;
return tableView;
}

public TableView TableView { get; }
public UIRefreshControl RefreshControl { get; private set; }
}
Чтобы уточнить: эти средства визуализации отлично работали в XF без каких-либо проблем.
Заранее благодарим вас за любые полезные предложения. что с этим делать.

Подробнее здесь: https://stackoverflow.com/questions/790 ... ntrenderer
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»