每个FlowListView单元格的不同图像

时间:2019-05-06 10:50:16

标签: c# xaml xamarin xamarin.forms

所以我有一个FlowListView,我想为FlowListView的每个单元格放置与默认图像不同的图像,但是我想通过if条件放置它,而if条件需要按钮的Text属性。我尝试在ViewModel和xaml.cs文件中执行此操作,但是在ViewModel中,我不知道如何获取按钮的Text属性,在xaml.cs文件中,我不知道如何在构造函数中执行此操作。

I have this

I want this

Xaml代码:

<flv:FlowListView FlowColumnCount="3" SeparatorVisibility="Default" HasUnevenRows="true" FlowColumnExpand="ProportionalLast"
                    FlowItemTappedCommand="{Binding ItemTappedCommand}" FlowLastTappedItem="{Binding LastTappedItem}"
                    FlowItemsSource="{Binding MyCategories}" >
            <flv:FlowListView.FlowColumnTemplate>
                <DataTemplate>
                    <Button Text="{Binding Name}"
                                Image="carne.png"
                                Command="{Binding IdCatalogs}"
                                CommandParameter="{Binding Id}"
                                TextColor="White"     
                                Clicked="ButtonSelected"                               
                                ContentLayout="Top"
                                BackgroundColor="#40000000"
                                BorderColor="#FFFFFF"
                                BorderWidth="2"
                                CornerRadius="6">
                    </Button>
                </DataTemplate>
            </flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>

Xaml.cs文件代码:

public partial class CategoriesMenuDetail : ContentPage
    {
        public Dictionary<int, Btn> buttons { get; set; }

        public CategoriesMenuDetail()
        {
            InitializeComponent();
            buttons = new Dictionary<int, Btn>();
        }

        public void ButtonSelected(object sender, EventArgs e)
        {          
            var button = (Button)sender;

            if (!buttons.ContainsKey(button.GetHashCode()))
            {
                buttons.Add(button.GetHashCode(), new Btn(button));
            }

            bool state = buttons[button.GetHashCode()].Toogle();

            if (button.Text == "Carnes")
            {
                var image = (state) ? "carneslc.png" : "carne.png";

                button.Image = image;
            }
            if (button.Text == "Peixes")
            {
                var image = (state) ? "peixeslc.png" : "peixe.png";

                button.Image = image;
            }
            if (button.Text == "Entradas")
            {
                var image = (state) ? "entradaslc.png" : "entrada.png";

                button.Image = image;
            }

            var bgColor = (state) ? Color.FromHex("#26047AD5") : Color.FromHex("#40000000");
            var borderColor = (state) ? Color.FromHex("#FF8A00") : Color.FromHex("#FFFFFF");

            button.BackgroundColor = bgColor;
            button.BorderColor = borderColor;
        }
    }

    public  class Btn
    {
        private Button _button { get; set; }

        private bool isToogle = false;

        public Btn(Button button)
        {
            _button = button;
        }

        public bool Toogle()
        {
            isToogle = !isToogle;
            return isToogle;
        }
    }

ViewModel代码:

 private RestaurantsClient restaurantsClient { get; set; }

        private ObservableCollection<CategoryDetail> _myCategories;
        public ObservableCollection<CategoryDetail> MyCategories
        {
            set
            {
                _myCategories = value;
                NotifyPropertyChanged(nameof(MyCategories));
            }
            get
            {
                return _myCategories;
            }
        }

        public RestaurantsReaderViewModel()
        {

            restaurantsClient = (App.Current as App).restaurantsClient;

            var restaurantsNames = restaurantsClient.GetCategoriesAsync(2).Result;
            MyCategories = new ObservableCollection<CategoryDetail>(restaurantsNames.Categories);
        }

CategoryDe​​tailModel:

public partial class CategoryDetail
    {
        [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)]
        public int Id { get; set; }

        [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public string Name { get; set; }

        public string ToJson()
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(this);
        }

        public static CategoryDetail FromJson(string data)
        {
            return Newtonsoft.Json.JsonConvert.DeserializeObject<CategoryDetail>(data);
        }

    }

2 个答案:

答案 0 :(得分:1)

您可以通过两种不同的方式解决此问题:

  1. 您可以创建一个ValueConverter,将您在CategoryDe​​tail上的ID或名称转换为图像路径,并将其绑定到Image属性。
  2. 将图像添加为CategoryDe​​tail中的属性并直接绑定

对于ValueConveter方法,您需要实现IValueConveter接口,它看起来可能像这样:

public class CategoryImageValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var name = (string)value;

        switch (name)
        {
            case "Entradas":
                return "entradas.png";
            case "Carnes":
                return "carnes.png";
            case "Peixes":
                return "peixes.png";

            // add more here
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后,您需要告诉Xamarin.Forms在哪里寻找此ValueConverter。因此,在页面上添加:

<ContentPage.Resources>
    <ResourceDictionary>
        <local:CategoryImageValueConverter x:Key="categoryImage" />
    </ResourceDictionary>
</ContentPage.Resources>

现在,您可以将Image属性的绑定更改为:

Image="{Binding Name, Converter{StaticResource categoryImage}}"

对于将其直接放入CategoryDe​​tail类的其他解决方案,您只需创建一个新属性,并使用正确的图像名称填充这些项目并绑定该属性。对于本示例,我们将其称为ImageName

Image="{Binding ImageName}"

在CategoryDe​​tail中看起来像这样:

private string _imageName;
public string ImageName
{
    get => _imageName;
    set
    {
        _imageName = value;
    }
}

如果您的CategoryDe​​tail类实现了InotifyPropertyChanged,请记住,如果稍后设置图像名称,也会触发PropertyChanged事件。

答案 1 :(得分:0)

您将Command按钮绑定到IdCatalog,可能是一个数字值,它应该是ICommand属性,并且您的VM应该如下所示:

public ICommand MyButtonCommand => new Command( (param) =>{ ... });
//Param is CommandParameter value, you should cast before use it

如果要使用UI的事件,首先必须从VM绑定Image属性,并将其设置为notificable属性。

如果将图像更改为代码,则不会通知UI值已更改。

已编辑:

您的结构良好的代码应该是这样

public partial class CategoriesMenuDetail : ContentPage
{
    public CategoriesMenuDetailViewModel ViewModel { get; set; }

    public CategoriesMenuDetail()
    {
        ViewModel = new CategoriesMenuDetailViewModel();

        InitializeComponent();

        BindingContext = Viewmodel;

    }
}


public class CategoriesMenuDetailViewModel 
{
    public List<CategoryDetail>MyCategories { get; set; } // if you don't add new items not need observable collection

    public ICommand ButtonClickedCommand => new Command((cParameter)=> ButtonclickedCommandExecute((CategoryDetail)cParameter)


    private void ButtonclickedCommandExecute(CategoryDetail myParam)
    {
        //Here goes you image's logic
        if (myParam.Name == "Carnes")
            myParam.ImageName = Image.FromFile("");
    }

}

public class CategoryDetail : ObservableObject
{
    public int Id { get; set; }
    private string _name;
    public string Name { get =>_name; set=>SetProperty(ref _name, value); }

    private string _imageName;
    public string  ImageName { get=>_imageName; set=>SetProperty(ref _imageName, value); }
}


public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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


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

        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

    }

和XAML

 <flv:FlowListView FlowColumnCount = "3" SeparatorVisibility="Default" HasUnevenRows="true" FlowColumnExpand="ProportionalLast"
                    FlowItemTappedCommand="{Binding ItemTappedCommand}" FlowLastTappedItem="{Binding LastTappedItem}"
                    FlowItemsSource="{Binding MyCategories}" >
            <flv:FlowListView.FlowColumnTemplate>
                <DataTemplate>
                    <Button Text = "{Binding Name}"
                                Image="{Binding ImageName}"
                                Command="{Binding ButtonClickedCommand}"
                                CommandParameter="{Binding .}"
                                TextColor="White"     
                                Clicked="ButtonSelected"                               
                                ContentLayout="Top"
                                BackgroundColor="#40000000"
                                BorderColor="#FFFFFF"
                                BorderWidth="2"
                                CornerRadius="6">
                    </Button>
                </DataTemplate>
            </flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>