在哪里执行内容视图业务逻辑操作

Where to do Content View Bussiness Logic Operations

提问人:okanalagas 提问时间:9/11/2023 最后编辑:okanalagas 更新时间:9/12/2023 访问量:109

问:

我正在开发一个 .net maui 应用程序,我需要在我的自定义控件中获取和设置数据。

目标是:

操作模板

页面:

    <ContentPage
    x:Class="V7.UIS.MauiMobile.Views.AboutPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:controls="clr-namespace:V7.UIS.MauiMobile.Controls.Views"    
    xmlns:viewmodel="clr-namespace:V7.UIS.MauiMobile.ViewModels"
    Title="About"
    ios:Page.UseSafeArea="true"
    x:DataType="viewmodel:AboutViewModel"
    BackgroundColor="{StaticResource NormalBackgroundColor}">

    <VerticalStackLayout>

        <controls:ItemBarcodeSearchView />

        <Entry Text="Count" />
        <Button
            Grid.Row="1"
            Grid.Column="1"
            Command="{Binding AddCommand}"
            Text="Add" />
    </VerticalStackLayout>
</ContentPage>

自定义控件 xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView
    x:Class="V7.UIS.MauiMobile.Controls.Views.ItemBarcodeSearchView"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:dxe="clr-namespace:DevExpress.Maui.Editors;assembly=DevExpress.Maui.Editors"
    x:Name="BarcodeSearchView">
    <ContentView.ControlTemplate>
        <ControlTemplate>
            <VerticalStackLayout>
                <Grid
                    x:Name="ButtonGrid"
                    Margin="5"
                    IsVisible="{TemplateBinding IsVisibleButtonGrid}">
                    <Button Clicked="ShowView" Text="Enter Barcode" />
                </Grid>
                <Grid
                    x:Name="DetailGrid"
                    Padding="15"
                    ColumnDefinitions="*"
                    ColumnSpacing="20"
                    IsVisible="{TemplateBinding IsVisibleDetailGrid}"
                    RowDefinitions="Auto,Auto"
                    VerticalOptions="Center">
                    <dxe:TextEdit
                        Grid.Row="0"
                        Margin="0"
                        ClearIconCommand="{TemplateBinding ClearFieldsCommand}"
                        ClearIconVisibility="Always"
                        LabelText="Barcode"
                        Text="{TemplateBinding Barcode}" />
                    <dxe:TextEdit
                        Grid.Row="1"
                        Margin="0"
                        ClearIconVisibility="Never"
                        LabelText="Item"
                        Text="{TemplateBinding ItemDescription}" />                    
                    <Button
                        Grid.Row="6"
                        Margin="0,10,0,0"
                        Command="{Binding Source={x:Reference BarcodeSearchView}, Path=Search}"
                        Text="Search" />
                    <Button
                        Grid.Row="7"
                        Margin="0,10,0,0"
                        Clicked="SendBarcodeDetails"
                        Text="Ok" />
                </Grid>
            </VerticalStackLayout>
        </ControlTemplate>
    </ContentView.ControlTemplate>
</ContentView>

当我按下搜索按钮时,我想执行此命令以设置项目描述。这是该内容视图的业务逻辑,我不想一遍又一遍地重复此代码。

private readonly HttpClient _client;

public blabla(IHttpClientFactory factory)
{
_client = factory?.CreateClient(AppConstants.ApiName);
}

GetBarcodeDetailQuery query = new()
{
    Barcode = barcode
};
await client.GetDataFromApi<GetBarcodeDetailQuery, GetBarcodeDetailViewModel>("Cards/ItemBarcode/GetBarcodeDetail", query, FindBarcodeCallBack);

我应该在哪里放置此操作以及如何放置此操作?我一个星期都想不通。

自定义控件 xaml.cs :

using CommunityToolkit.Mvvm.Input;
using V7.UIS.MauiMobile.Models;

namespace V7.UIS.MauiMobile.Controls.Views;

public partial class ItemBarcodeSearchView : ContentView
{
    public ItemBarcodeSearchView()
    {
        InitializeComponent();
        IsVisibleButtonGrid = "true";
        IsVisibleDetailGrid = "false";
    }

    public event EventHandler<ItemBarcodeDetail> BarcodeDetailsReady;

    public static readonly BindableProperty BarcodeProperty =
        BindableProperty.Create(nameof(Barcode), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty ItemDescriptionProperty =
        BindableProperty.Create(nameof(ItemDescription), typeof(string), typeof(ItemBarcodeSearchView));    
    public static readonly BindableProperty IsVisibleButtonGridProperty =
        BindableProperty.Create(nameof(IsVisibleButtonGrid), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty IsVisibleDetailGridProperty =
        BindableProperty.Create(nameof(IsVisibleDetailGrid), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty SearchProperty =
            BindableProperty.Create(nameof(Search), typeof(RelayCommand), typeof(ItemBarcodeSearchView));

    public RelayCommand Search
    {
        get => (RelayCommand)GetValue(SearchProperty);
        set => SetValue(SearchProperty, value);
    }
    public string IsVisibleButtonGrid
    {
        get => (string)GetValue(IsVisibleButtonGridProperty);
        set => SetValue(IsVisibleButtonGridProperty, value);
    }
    public string IsVisibleDetailGrid
    {
        get => (string)GetValue(IsVisibleDetailGridProperty);
        set => SetValue(IsVisibleDetailGridProperty, value);
    }
    public string Barcode
    {
        get => (string)GetValue(BarcodeProperty);
        set => SetValue(BarcodeProperty, value);
    }
    public string ItemDescription
    {
        get => (string)GetValue(ItemDescriptionProperty);
        set => SetValue(ItemDescriptionProperty, value);
    }
    
    [RelayCommand]
    public void ClearFields()
    {
        Barcode = string.Empty;
        ItemDescription = string.Empty;        
    }

    private void SendBarcodeDetails(object sender, EventArgs e)
    {
        ItemBarcodeDetail itemBarcodeDetail = new()
        {
            Barcode = Barcode,
            ItemDescription = ItemDescription            
        };
        BarcodeDetailsReady?.Invoke(sender, itemBarcodeDetail);
        IsVisibleButtonGrid = "true";
        IsVisibleDetailGrid = "false";
    }
    private void ShowView(object sender, EventArgs e)
    {
        IsVisibleButtonGrid = "false";
        IsVisibleDetailGrid = "true";
    }
}

希望这里有人能帮助我。

C# XAML Xamarin Maui 自定义控件

评论

1赞 Eldar 9/11/2023
这回答了你的问题吗?从 XAML 调用参数化构造函数
0赞 okanalagas 9/11/2023
@H.A.H. 谢谢你的回答,但我也问了这个问题:ContentView 应该有业务逻辑,还是我应该把它绑定到 ViewModel 或其他我找不到答案的东西
0赞 H.A.H. 9/11/2023
@Okanalagas 所有业务逻辑都属于 ViewModel。该 ViewModel 可以保存对其他类的引用,这些类包含可重用的代码,有时称为“Services”。不惜一切代价避免将业务逻辑放在 ContentView(页面、自定义控件或其他内容)中。我正在使用 CommunityToolkit.MVVM。强烈推荐它用于 MAUI。

答:

0赞 Jessie Zhang -MSFT 9/11/2023 #1

该类定义一个 View 类型的 Content 属性,该属性表示 .此属性由对象支持,这意味着它可以是数据绑定的目标,并设置样式。ContentViewContentViewBindableProperty

ContentView 类本身提供的功能很少,但可用于创建自定义控件。创建自定义控件的过程是:

  • 创建一个派生自 ContentView 类的类。
  • 在代码隐藏文件中定义任何控件属性或事件 自定义控件。
  • 定义自定义控件的 UI。

有关详细信息,您可以查看官方文档:创建自定义控件

注意:

您还可以在此处查看示例:ContentView 演示,它将帮助您了解如何使用 创建自定义控件。尽管此示例是 Xamarin 窗体的应用,但它也适用于 MAUI。ContentView

评论

0赞 okanalagas 9/11/2023
我可以在自定义控件中使用 httpclientfactory 等服务吗?对于重复操作是否最好这样做
0赞 Jessie Zhang -MSFT 9/11/2023
ContentView是用于显示各种 UI 的控件,并且是可重用的。对于 service 之类的代码,我们一般不建议将其添加到 .我们经常使用 MVVM 实现,经常将服务请求等代码放在 ViewModel 中。有关 MVVM 的更多信息,可以查看文档模型-视图-视图模型模式httpclientContentView
0赞 Jessie Zhang -MSFT 9/12/2023
嗨,@Okanalagas,我们通常为页面设置 t 而不是 customview(例如)。您可以将 添加到页面的 ViewModel 中,并在页面的 ViewModel 中请求数据。关于这一点,有一些类似的线程,你可以在这里检查它们:线程 1线程 2BindContextItemBarcodeSearchView HttpClient
0赞 okanalagas 9/12/2023
感谢您的回答,但我仍然想问这个问题。我想在多个地方使用此组件。这种方法不会导致代码重复吗?
0赞 Jessie Zhang -MSFT 9/12/2023
是的,自定义控件本身可以重用。我们只需要向它传递必要的参数。
0赞 okanalagas 9/12/2023 #2

我做了这样的事情,它有效,但使用我不确定是最佳做法。

这是页面:

<ContentPage    
    xmlns:viewmodel="clr-namespace:V7.UIS.MauiMobile.ViewModels"
    x:DataType="viewmodel:AboutViewModel"
    Title="About">
    <VerticalStackLayout>

        <controls:ItemBarcodeSearchView HttpClient="{Binding HttpClient}" />

        <Entry Text="Count" />
        <Button
            Grid.Row="1"
            Grid.Column="1"
            Text="Add"/>
    </VerticalStackLayout>
</ContentPage>
using V7.UIS.MauiMobile.Constants;

namespace V7.UIS.MauiMobile.ViewModels
{
    public class AboutViewModel : BaseViewModel
    {
        private readonly HttpClient _client;

        public const string ViewName = "AboutPage";

        public AboutViewModel(IHttpClientFactory factory)
        {
            Title = "About";
            _client = factory?.CreateClient(AppConstants.ApiName);
        }
        public HttpClient HttpClient => _client;
    }
}

下面是自定义控件:

using CommunityToolkit.Mvvm.Input;
using V7.BaseApplication.AppModels.Erp.Cards.Item.ItemBarcode.Queries;
using V7.BaseApplication.AppModels.Erp.Cards.Item.ItemBarcode.ViewModel;
using V7.UIS.MauiMobile.Helpers;
using V7.UIS.MauiMobile.Models;

namespace V7.UIS.MauiMobile.Controls.Views;

public partial class ItemBarcodeSearchView : ContentView
{
    public ItemBarcodeSearchView()
    {
        InitializeComponent();
        IsVisibleButtonGrid = "true";
        IsVisibleDetailGrid = "false";
    }

    public event EventHandler<ItemBarcodeDetail> BarcodeDetailsReady;

    #region PropertyDefinition 

    public static readonly BindableProperty BarcodeProperty =
        BindableProperty.Create(nameof(Barcode), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty ItemDescriptionProperty =
        BindableProperty.Create(nameof(ItemDescription), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty ItemUnitProperty =
        BindableProperty.Create(nameof(ItemUnit), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty ItemLotProperty =
        BindableProperty.Create(nameof(ItemLot), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty ItemSerialNumberProperty =
        BindableProperty.Create(nameof(ItemSerialNumber), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty QuantityProperty =
        BindableProperty.Create(nameof(Quantity), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty IsVisibleButtonGridProperty =
        BindableProperty.Create(nameof(IsVisibleButtonGrid), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty IsVisibleDetailGridProperty =
        BindableProperty.Create(nameof(IsVisibleDetailGrid), typeof(string), typeof(ItemBarcodeSearchView));
    public static readonly BindableProperty HttpClientProperty =
            BindableProperty.Create(nameof(HttpClient), typeof(HttpClient), typeof(ItemBarcodeSearchView));
    public HttpClient HttpClient
    {
        get => (HttpClient)GetValue(HttpClientProperty);
        set => SetValue(HttpClientProperty, value);
    }
    public string IsVisibleButtonGrid
    {
        get => (string)GetValue(IsVisibleButtonGridProperty);
        set => SetValue(IsVisibleButtonGridProperty, value);
    }
    public string IsVisibleDetailGrid
    {
        get => (string)GetValue(IsVisibleDetailGridProperty);
        set => SetValue(IsVisibleDetailGridProperty, value);
    }
    public string Barcode
    {
        get => (string)GetValue(BarcodeProperty);
        set => SetValue(BarcodeProperty, value);
    }
    public string ItemDescription
    {
        get => (string)GetValue(ItemDescriptionProperty);
        set => SetValue(ItemDescriptionProperty, value);
    }
    public string ItemUnit
    {
        get => (string)GetValue(ItemUnitProperty);
        set => SetValue(ItemUnitProperty, value);
    }
    public string ItemLot
    {
        get => (string)GetValue(ItemLotProperty);
        set => SetValue(ItemLotProperty, value);
    }
    public string ItemSerialNumber
    {
        get => (string)GetValue(ItemSerialNumberProperty);
        set => SetValue(ItemSerialNumberProperty, value);
    }
    public string Quantity
    {
        get => (string)GetValue(QuantityProperty);
        set => SetValue(QuantityProperty, value);
    }
    #endregion

    private void ShowView(object sender, EventArgs e)
    {
        IsVisibleButtonGrid = "false";
        IsVisibleDetailGrid = "true";
    }

    [RelayCommand]
    public void ClearFields()
    {
        Barcode = string.Empty;
        ItemDescription = string.Empty;
        ItemUnit = string.Empty;
        ItemLot = string.Empty;
        ItemSerialNumber = string.Empty;
        Quantity = string.Empty;
    }
    [RelayCommand]
    public async Task Search()
    {
        await FindItemDetails(Barcode, HttpClient);
    }

    public async Task FindItemDetails(string barcode, HttpClient client)
    {
        if (!string.IsNullOrEmpty(barcode))
        {
            GetBarcodeDetailQuery query = new()
            {
                Barcode = barcode
            };
            await client.GetDataFromApi<GetBarcodeDetailQuery, GetBarcodeDetailViewModel>("Cards/ItemBarcode/GetBarcodeDetail", query, FindBarcodeCallBack);
        }
        else
        {
            await Shell.Current.DisplayAlert("Hata", "Lütfen bir barkod giriniz.", "Ok");
        }
    }

    void FindBarcodeCallBack(GetBarcodeDetailViewModel vm)
    {
        ItemDescription = vm.Item.Description;
        ItemUnit = vm.ItemUnits.FirstOrDefault().ToString();
        ItemLot = vm.Lot.ToString();
        ItemSerialNumber = vm.SerialNumber.ToString();
        Quantity = "0";
    }

    private void SendBarcodeDetails(object sender, EventArgs e)
    {
        ItemBarcodeDetail itemBarcodeDetail = new()
        {
            Barcode = Barcode,
            ItemDescription = ItemDescription,
            ItemUnit = ItemUnit,
            ItemLot = ItemLot,
            ItemSerialNumber = ItemSerialNumber,
            Quantity = Quantity,
        };
        BarcodeDetailsReady?.Invoke(sender, itemBarcodeDetail);
        IsVisibleButtonGrid = "true";
        IsVisibleDetailGrid = "false";
    }
}

评论

0赞 Amit Mohanty 9/13/2023
您需要对回复中分享的内容进行说明。