xamarin 我将如何创建一个自定义命令的数量控制在mvvm的形式

6ju8rftf  于 2023-05-27  发布在  其他
关注(0)|答案(1)|浏览(142)

我想创建一个自定义命令控件来处理数量控制使用一个条目和2个按钮
我有一个mvvm页面,标签和按钮显示在视图模型数据模板中,我的按钮工作,它们改变了从mysql数据库中提取的数据,但它没有更新数量控制(条目)的可视端。

public class ProductDetailsViewModel : BaseProductDetailsViewModel
    {

        public string strOrderNumber3 = SigninPage.strOrderNumber;
        public string strEmail1 = SigninPage.strEmail;
        private string _productname;
        public string QuantityNew1 = string.Empty;

        private ICommand _quantityaddCommand;

        public ICommand QuantityAddCommand
        {
            get
            {
                if (_quantityaddCommand == null)
                {
                    _quantityaddCommand = new Command<ProductDetail>(async (productdetail) =>
                    {
                        await OnQuantityAddSelected(productdetail);
                    });
                }

                return _quantityaddCommand;
            }
        }


        private async Task OnQuantityAddSelected(ProductDetail productdetail)
        {
            productdetail.Quantity = (Convert.ToInt32(productdetail.QuantityOld) + Convert.ToInt32(1)).ToString();
            productdetail.QuantityOld = productdetail.Quantity;

            OnPropertyChanged(productdetail.QuantityOld);
            RefreshCanExcutes();
            
        }

        

        private ICommand _quantityminusCommand;

        public ICommand QuantityMinusCommand
        {
            get
            {
                if (_quantityminusCommand == null)
                {
                    _quantityminusCommand = new Command<ProductDetail>(async (productdetail) =>
                    {
                        await OnQuantityMinusSelected(productdetail);
                    });
                }

                return _quantityminusCommand;
            }
        }


        private async Task OnQuantityMinusSelected(ProductDetail productdetail)
        {
            if (productdetail.Quantity != "0")
            {

                productdetail.Quantity = (Convert.ToInt32(productdetail.QuantityOld) - Convert.ToInt32(1)).ToString();
                productdetail.QuantityOld = productdetail.Quantity;

                OnPropertyChanged("productdetail.QuantityOld");
                RefreshCanExcutes();

            }

        }

        private void RefreshCanExcutes()
        {
            (QuantityAddCommand as Command).ChangeCanExecute();
            (QuantityMinusCommand as Command).ChangeCanExecute();
            
        }

        public string ProductName
        {
            get { return _productname; }
            set { _productname = value; }
        }

        public ProductDetailsViewModel(string productparamter)
        {
            _productname = productparamter;
            
        }

        


        private ICommand _loadProductDetailsCommand;

        public ICommand LoadProductDetailsCommand
        {
            get
            {
                if (_loadProductDetailsCommand == null)
                {
                    _loadProductDetailsCommand = new Command(async () => await LoadProductDetails());
                }

                return _loadProductDetailsCommand;
            }
        }

        private List<ProductDetail> _productdetails;

        public List<ProductDetail> ProductDetails
        {
            get => _productdetails;
            set => SetProperty(ref _productdetails, value);
        }

        public async Task LoadProductDetails()
        {
            // Call the GetCategories method to load the categories from the database
            ProductDetails = await GetProductDetails();
        }

        // Method for downloading an image
        private async Task<byte[]> DownloadImageAsync(string url)
        {
            using (var httpClient = new HttpClient())
            {
                return await httpClient.GetByteArrayAsync(url);
            }
        }

        // Method for getting the categories from the database
        private async Task<List<ProductDetail>> GetProductDetails()
        {
            // Initialize the list of categories
            List<ProductDetail> productdetails = new List<ProductDetail>();

            // Connect to the database
            using (MySqlConnection connection = new MySqlConnection("mysql string"))
            {
                connection.Open();

                // Create a command to select the categories from the database
                using (MySqlCommand command = new MySqlCommand("SELECT name, productdetails, price, image, quantity FROM products WHERE name = '" + ProductName + "' ", connection))
                {
                    // Execute the command and read the results
                    using (MySqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            if (reader.FieldCount >= 5)
                            {
                                // Create a new category object
                                ProductDetail productdetail = new ProductDetail
                                {
                                    Name = reader.GetString(0),
                                    ProductDetails = reader.GetString(1),
                                    Price = "R " + reader.GetString(2),
                                    Price1 = reader.GetString(2),
                                    ImageUrl = reader.GetString(3),
                                    Quantity = reader.GetString(4),
                                    QuantityOld = reader.GetString(4),
                                    
                                };
                                
                                
                                // Download the image for the category
                                productdetail.ImageData = await DownloadImageAsync(productdetail.ImageUrl);

                                // Add the category to the list
                                productdetails.Add(productdetail);
                            }
                        }

                    }
                }
            }

            // Return the list of categories
            return productdetails;

        
        }
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App2.Views.ProductDetails"
             BackgroundImageSource="bckgrnd20Darken.jpg"
             >

    <StackLayout Padding="10">
        <Entry x:Name="txtQuantity" IsReadOnly="True" BindingContext="{Binding Quantity, Mode=OneWayToSource}"/>
        <Entry x:Name="txtQuantityOld" IsReadOnly="True"/>
        <Label x:Name="txtOrderNumber"/>
        <CollectionView x:Name="productdetailsCollectionView" ItemsSource="{Binding ProductDetails}" >
            <CollectionView.ItemsLayout>
                <GridItemsLayout Orientation="Vertical" Span="1" />
            </CollectionView.ItemsLayout>
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout HorizontalOptions="Center" VerticalOptions="CenterAndExpand" Margin="0" Padding="7" >
                        <Frame HasShadow="False" BorderColor="Black"  BackgroundColor="Transparent" CornerRadius="20">
                            <StackLayout Padding="5">
                                <Image Source="{Binding ImageUrl}" HeightRequest="200" />
                                <Label Text="{Binding Name}" FontSize="Title" FontAttributes="Bold" HorizontalTextAlignment="Center" TextColor="Black" Padding="10" />
                                <Label Text="About This Product" FontSize="Large" FontAttributes="Bold" Margin="10,10,10,10" TextColor="Black"/>
                                <Label Text="{Binding ProductDetails}" Margin="10,10,10,10" FontSize="Large" HorizontalTextAlignment="Start" VerticalTextAlignment="Center" TextColor="White"/>
                                <Label Text="{Binding Price}" Margin="10,10,10,10" FontSize="Title" FontAttributes="Bold" TextColor="Black" />
                                <Label Text="{Binding Price1}" IsVisible="false"/>
                                <StackLayout Orientation="Horizontal">
                                    <Button
                                        x:Name="minusbutton"
                                        ImageSource="minus.png" 
                                        Command="{Binding Source={x:Reference productdetailsCollectionView}, Path=BindingContext.QuantityMinusCommand}"
                                        CommandParameter="{Binding .}"
                                        BackgroundColor="Transparent"/>
                                    <Entry Text="{Binding Quantity}"/>
                                    <Entry Text="{Binding QuantityOld}"/>
                                    <Entry Text="{Binding QuantityNew, Mode=TwoWay}"/>
                                    <Button
                                        ImageSource="Plus.png"
                                        Command="{Binding Source={x:Reference productdetailsCollectionView}, Path=BindingContext.QuantityAddCommand}"
                                        CommandParameter="{Binding .}"
                                        BackgroundColor="Transparent"/>
                                </StackLayout>
                                <Button
                                    Command="{Binding Source={x:Reference productdetailsCollectionView}, Path=BindingContext.ProductDetailsCommand}" 
                                    CommandParameter="{Binding .}"
                                    Text="ADD TO CART"
                                    CornerRadius="20"
                                    BackgroundColor="Blue"
                                    TextColor="White"/>
                            </StackLayout>
                        </Frame>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
        
    </StackLayout>

</ContentPage>

公共类BaseProductDetailsViewModel:INotifyPropertyChanged {

public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    //protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    //{
    //    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    //}

    protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value))
            return false;

        backingStore = value;
        OnPropertyChanged(propertyName);

        return true;
    }

    // Method for showing alerts
    protected async Task ShowAlert(string title, string message, string buttonText)
    {
        await Application.Current.MainPage.DisplayAlert(title, message, buttonText);
    }
}

public partial class ProductDetails : ContentPage
{
    public static string strOrderNumber1 = SigninPage.strOrderNumber;
    
    public ProductDetails(string ProductName)
    {
        
        InitializeComponent();

        BindingContext = new ProductDetailsViewModel(ProductName);

        // Call the method to load the categories from the database
        ((ProductDetailsViewModel)BindingContext).LoadProductDetailsCommand.Execute(null);

        //txtQuantity.Text = strQuantity;
        //txtQuantityOld.Text = strQuantityOld;
        //txtQuantity.Text = txtQuantityOld.Text;
        //txtQuantity.Text = "0";
        //txtQuantityOld.Text = "0";
        
        txtOrderNumber.Text = strOrderNumber1;

        //strQuantity = txtQuantity.Text;
        //strQuantityOld = txtQuantityOld.Text;



    }
cczfrluj

cczfrluj1#

请重新检查您的型号ProductDetail是否实现了接口INotifyPropertyChanged
从文档INotifyPropertyChanged Interface中,我们可以知道:
INotifyPropertyChanged接口用于通知客户端(通常是绑定客户端)属性值已更改。
基于你的代码,我创建了一个demo来实现这个功能.
可以参考以下代码:

ProductDetail.cs

public class ProductDetail: INotifyPropertyChanged 
{
    public string ProductName{ get; set; }
    //public string Quantity { get; set; }

    private string _quantity;
    public string Quantity
    {
        set { SetProperty(ref _quantity, value); }
        get { return _quantity; }
    }

    // public string QuantityOld { get; set; }
    private string _quantityOld;
    public string QuantityOld
    {
        set { SetProperty(ref _quantityOld, value); }
        get { return _quantityOld; }
    }

    //public string QuantityNew { get; set; }
    private string _quantityNew;
    public string QuantityNew
    {
        set { SetProperty(ref _quantityNew, value); }
        get { return _quantityNew; }
    }

    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;
        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

TestViewModel.cs

public class TestViewModel 
    {

        public ObservableCollection<ProductDetail> Items { get; set; }

        public ICommand QuantityAddCommand { get; set; }
        public ICommand QuantityMinusCommand { get; set; }

        public TestViewModel() {
            Items= new ObservableCollection<ProductDetail>();
            Items.Add(new ProductDetail {  ProductName="Product1", Quantity = "30", QuantityOld="10",QuantityNew="0" });
            Items.Add(new ProductDetail { ProductName = "Product1", Quantity = "40", QuantityOld = "10", QuantityNew = "0" });
            Items.Add(new ProductDetail { ProductName = "Product1", Quantity = "50", QuantityOld = "10", QuantityNew = "0" });

            QuantityAddCommand = new Command((object item) => {

                if (item != null && item is ProductDetail) {
                    ProductDetail productdetail = (ProductDetail)item;
                    productdetail.Quantity = (Convert.ToInt32(productdetail.QuantityOld) + Convert.ToInt32(1)).ToString();
                    productdetail.QuantityOld = productdetail.Quantity;
                
                }
            });

            QuantityMinusCommand = new Command((object item) => {
                if (item != null && item is ProductDetail)
                {

                    ProductDetail productdetail = (ProductDetail)item;

                    if (productdetail.Quantity != "0")
                    {
                        productdetail.Quantity = (Convert.ToInt32(productdetail.QuantityOld) - Convert.ToInt32(1)).ToString();
                        productdetail.QuantityOld = productdetail.Quantity;

                    }
                }
            });
        }

        bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Object.Equals(storage, value))
                return false;
            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

使用示例:

<?xml version="1.0" encoding="utf-8" ?> 
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:formcollectionviewapp="clr-namespace:FormCollectionViewApp"
             x:Class="FormCollectionViewApp.MainPage">

    <ContentPage.BindingContext>
        <formcollectionviewapp:TestViewModel></formcollectionviewapp:TestViewModel>
    </ContentPage.BindingContext>

    <CollectionView  ItemsSource="{Binding Items}" x:Name="productdetailsCollectionView">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <StackLayout Orientation="Horizontal">
                    <Button    
                                        x:Name="minusbutton" Text="minus"
                                        Command="{Binding Source={x:Reference productdetailsCollectionView}, Path=BindingContext.QuantityMinusCommand}"
                                        CommandParameter="{Binding .}"
                                        BackgroundColor="Transparent"/>
                    <Entry x:Name="txtQuantity" IsReadOnly="True" Text="{Binding Quantity}" />

                    <Entry x:Name="txtQuantityOld" IsReadOnly="True" Text="{Binding QuantityOld}" />

                    <Entry Text="{Binding QuantityNew}"/>
                    <Button   Text="add"
                                        ImageSource="Plus.png"
                                        Command="{Binding Source={x:Reference productdetailsCollectionView}, Path=BindingContext.QuantityAddCommand}"
                                        CommandParameter="{Binding .}"
                                        BackgroundColor="Transparent"/>

                    <!--<Button Text="Remove"   Command="{Binding BindingContext.DeleteItemCommand, Source={x:Reference mCollectionView}}"  CommandParameter="{Binding .}"  Margin="10,0,10,0" WidthRequest="80" HorizontalOptions="End"/>-->

                </StackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

</ContentPage>

注:

同时,您可以简化命令代码。
例如:

public ICommand QuantityAddCommand { get; set; }
        public ICommand QuantityMinusCommand { get; set; }

并在视图模型的构造函数上初始化这两个命令:

QuantityAddCommand = new Command((object item) => {

                if (item != null && item is ProductDetail) {
                    ProductDetail productdetail = (ProductDetail)item;
                    productdetail.Quantity = (Convert.ToInt32(productdetail.QuantityOld) + Convert.ToInt32(1)).ToString();
                    productdetail.QuantityOld = productdetail.Quantity;
                
                }
            });

            QuantityMinusCommand = new Command((object item) => {
                if (item != null && item is ProductDetail)
                {

                    ProductDetail productdetail = (ProductDetail)item;

                    if (productdetail.Quantity != "0")
                    {
                        productdetail.Quantity = (Convert.ToInt32(productdetail.QuantityOld) - Convert.ToInt32(1)).ToString();
                        productdetail.QuantityOld = productdetail.Quantity;

                    }
                }
            });
        }

更新:

既然你已经为你的应用程序使用了MVVM,为什么你要在ProductDetails.xmls.cs页面中调用LoadProductDetailsCommand命令?

((ProductDetailsViewModel)BindingContext).LoadProductDetailsCommand.Execute(null);

你可以删除它:

public partial class ProductDetails: ContentPage 
{
    public ProductDetails()
    {
        InitializeComponent();

        BindingContext = new TestViewModel("test");

        // Call the method to load the categories from the database
        //((TestViewModel)BindingContext).LoadProductDetailsCommand.Execute(null);
    }
}

你可以在视图模型ProductDetailsViewModel.cs的构造函数上从数据库中获取数据,如下所示:

public  ProductDetailsViewModel(string productname)
    {

        //other code 

        _productname = productname;

        //load data from database here
        LoadProductDetails();
    }

此外,我建议您将ProductDetails的类型定义为ObservableCollection<T>

private ObservableCollection<ProductDetail> _productdetails;

    public ObservableCollection<ProductDetail> ProductDetails
    {
        get => _productdetails;
        set => SetProperty(ref _productdetails, value);
    }

在这种情况下,一旦向ProductDetails添加或删除项,UI将自行刷新。

相关问题