如何在Xamarin Forms中引用列表视图中的自定义滑块

qyzbxkaa  于 2023-04-03  发布在  其他
关注(0)|答案(1)|浏览(135)

我有一个自定义的滑块,并试图把它放在一个列表视图与网格,使列表视图显示以下内容:左上:列表中的字符串项。左下:(在每个项目下)自定义滑块。(向右/第二列:每个项目的整数/数字值)。
自定义滑块是用NuGet包SkiaSharp制作的,名为“x:Name=“balloon_slider”"。当我把自定义滑块放在xaml中的列表视图中时-它不再能在C#中引用(在当前上下文中不存在)。(它在列表视图之外工作。)下面是列表视图的xaml代码:

<ListView x:Name="displaylist100" HasUnevenRows="True">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <ViewCell>
                                    <Grid >
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="1*" />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>

                                        <!--Items from list as strings-->

                                        <Grid Grid.Column="0">                  
                                            <Label x:Name="listlabel"
                                                Text="{Binding Text}"
                                                HorizontalTextAlignment="Center"
                                                FontSize="Medium" 
                                                VerticalOptions="CenterAndExpand" 
                                                HorizontalOptions="CenterAndExpand"
                                                Padding="10, 10"
                                                Margin="0,5,5,0"/>

                                            <!--SkiaSharp Balloon_slider-->

                                            <Grid>
                                            <skia:SKCanvasView x:Name="balloon_slider"      
                                             PaintSurface="Handle_Slider_PaintSurface"/>
                                            <local:BalloonView x:Name="balloonSvg"/>
                                            <Grid.Effects>
                                                <local:TouchEffect        
                                                TouchAction="Handle_TouchAction"/>
                                            </Grid.Effects>
                                            </Grid> 

                                            <!--Value displayed to the right-->

                                            <Label Text="{Binding DisplayValue, Mode=TwoWay}" 
                                            FontSize="Medium"
                                            VerticalOptions="CenterAndExpand"
                                            HorizontalOptions="Center"
                                            Padding="10, 10"
                                            Grid.Column="1"/>
                                        </Grid>
                                    </Grid>
                                </ViewCell>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>

我使用的滑块是这个的定制版本:“https://github.com/memsranga/Balloony网站“。
我试着用这个:“var balloon_slider =(SKCanvasView)listView.FindByName(“气球滑块”);在“InitializeComponent()”中;“部分-但它似乎并没有使它连接两者。我也试图在列表视图中有一个标准的滑块-这是可行的。所以我的问题是:我怎么能引用滑块从我的C#背后时,它是在列表视图?
更新:这是气球滑块项目的代码-我有点困惑,我需要改变什么才能进行绑定。目前,每个“balloon_slider”和“balloonSvg”都有错误,即找不到:

using System;
using System.Diagnostics;
using System.Xml.Linq;
using SkiaSharp;
using SkiaSharp.Views.Forms;
using Xamarin.Forms;
using static Balloony.TouchEffect;

namespace Balloony
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();


            SliderSelectedPaint = new SKPaint
            {
                Color = Color.FromHex("#eb0000").ToSKColor(),
                IsAntialias = true,
                Style = SKPaintStyle.Fill,
                StrokeWidth = SliderHeight
            };

            SliderUnSelectedPaint = new SKPaint
            {
                Color = Color.FromHex("#f8f8f8").ToSKColor(),
                IsAntialias = true,
                Style = SKPaintStyle.Stroke,
                StrokeWidth = SliderHeight
            };

            ThumbPaint = new SKPaint
            {
                Color = Color.FromHex("#eb0000").ToSKColor(),
                IsAntialias = true,
                Style = SKPaintStyle.Fill
            };
            ThumbSelectedPaint = new SKPaint
            {
                Color = Color.FromHex("#eb0000").ToSKColor(),
                IsAntialias = true,
                Style = SKPaintStyle.Stroke,
                StrokeWidth = SelectedThumbThickness
            };
            ThumbSelectedSubtractPaint = new SKPaint
            {
                Color = Color.Transparent.ToSKColor(),
                IsAntialias = true,
                Style = SKPaintStyle.Fill,
                StrokeWidth = 0,
                BlendMode = SKBlendMode.Src
            };
            ThumbSubtractPaint = new SKPaint
            {
                Color = Color.Transparent.ToSKColor(),
                IsAntialias = true,
                Style = SKPaintStyle.Fill,
                StrokeWidth = 0,
                BlendMode = SKBlendMode.Src
            };

            Percent = 50;
        }

        float SliderHeight = 5;
        float SelectedThumbThickness = 10;
        float ThumbSize = 50;
        SKPaint SliderSelectedPaint { get; set; }
        SKPaint SliderUnSelectedPaint { get; set; }
        SKPaint ThumbPaint { get; set; }
        SKPaint ThumbSubtractPaint { get; set; }
        SKPaint ThumbSelectedPaint { get; set; }
        SKPaint ThumbSelectedSubtractPaint { get; set; }
        private TouchActionType _touchType;
        private double _width;
        private float _percent;

        public float Percent
        {
            get => _percent;
            private set
            {
                _percent = value;
                balloon_slider.InvalidateSurface();
                TranslateBalloon(Percent);
            }
        }

        protected override void OnSizeAllocated(double width, double height)
        {
            base.OnSizeAllocated(width, height);

            // only calling when orientation changes
            if (Math.Abs(width - _width) > 0.01)
            {
                _width = width;
                balloonSvg.AnchorY = 1;
                balloonSvg.TranslationX = (balloon_slider.Width * Percent / 100) - balloonSvg.Width / 2;
                balloonSvg.Scale = 0;
                balloonSvg.TranslationY = balloon_slider.Height;
            }
        }

        void Handle_Slider_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
        {
            var info = e.Info;
            var canvas = e.Surface.Canvas;

            canvas.Clear();

            DrawSlider(canvas, info, Percent);
            DrawThumb(canvas, info, Percent, _touchType);
        }

        private void TranslateBalloon(float percent)
        {
            if (this.AnimationIsRunning("TranslationAnimation"))
            {
                return;
            }

            var oldX = balloonSvg.TranslationX;
            var newX = balloon_slider.Width * percent / 100 - balloonSvg.Width / 2;
            balloonSvg.Text = Math.Floor(Percent).ToString();

            var translation = new Animation();
            translation.Add(0, 1, new Animation((s) =>
            {
                if (oldX > newX)
                {
                    var delta = oldX - s * Math.Abs(oldX - newX);
                    balloonSvg.TranslationX = delta;
                }
                else
                {
                    var delta = oldX + s * Math.Abs(oldX - newX);
                    balloonSvg.TranslationX = delta;
                }
            }, 0, 1));
            translation.Add(0, 1, new Animation(s =>
            {
                if (oldX > newX)
                {
                    var delta = oldX - s * Math.Abs(oldX - newX);
                    var angle = Math.Abs(oldX - newX) > 0.001 ? Math.Tanh((oldX - newX) / balloon_slider.Width) : 0;
                    balloonSvg.Rotation = angle * 180;
                }
                else
                {
                    var delta = oldX + s * Math.Abs(oldX - newX);
                    var angle = Math.Abs(oldX - newX) > 0.001 ? Math.Tanh((oldX - newX) / balloon_slider.Width) : 0;
                    balloonSvg.Rotation = angle * 180;
                }
            }, 0, 1, finished: () =>
            {
                balloonSvg.RelRotateTo(-balloonSvg.Rotation, 500);
            }));
            translation.Commit(balloonSvg, "TranslationAnimation", length: 100);
        }

        private void DrawThumb(SKCanvas canvas, SKImageInfo info, float percent, TouchActionType touchActionType)
        {
            var y = info.Height - ThumbSize - SelectedThumbThickness;
            var center = info.Width * percent / 100;

            if (touchActionType == TouchActionType.Pressed || touchActionType == TouchActionType.Moved)
            {
                // selected thumb
                var radius = ThumbSize * 0.5f; // 50% of size
                canvas.DrawCircle(center, y, radius, ThumbSelectedPaint);
                canvas.DrawCircle(center, y, radius, ThumbSelectedSubtractPaint);
                return;
            }

            //default thumb
            var startX = center - ThumbSize / 2;
            var startY = y - ThumbSize / 2;
            var cornerRadius = ThumbSize * 0.4f; // 40% of size
            var innerRadius = ThumbSize / 2 * .5f; // 50 % of side
            canvas.DrawRoundRect(startX, startY, ThumbSize, ThumbSize, cornerRadius, cornerRadius, ThumbPaint);
            canvas.DrawCircle(center, y, innerRadius, ThumbSubtractPaint);
        }

        private void Handle_TouchAction(object sender, Balloony.TouchEffect.TouchActionEventArgs args)
        {
            _touchType = args.Type;
            if (this.AnimationIsRunning("FloatAnimation") || this.AnimationIsRunning("DropAnimation"))
            {
                return;
            }
            if (_touchType == TouchActionType.Pressed || _touchType == TouchActionType.Entered)
            {
                Debug.WriteLine("entered");
                var floatAnimation = new Animation();
                floatAnimation.Add(0, 1, new Animation((s) =>
                {
                    balloonSvg.Scale = s;
                    balloonSvg.TranslationY = (balloon_slider.Height - balloonSvg.Height - 88) - s * -45;
                }, 0, 1));
                floatAnimation.Commit(balloonSvg, "FloatAnimation");
            }
            else if (_touchType == TouchActionType.Released || _touchType == TouchActionType.Exited)
            {
                var dropAnimation = new Animation();
                dropAnimation.Add(0, 1, new Animation((s) =>
                {
                    balloonSvg.Scale = s;
                    balloonSvg.TranslationY = (balloon_slider.Height - balloonSvg.Height - 88) - s * -45;
                }, 1, 0));
                dropAnimation.Commit(balloonSvg, "DropAnimation");
            }
            Percent = (float)((args.Location.X / balloon_slider.Width) * 100 - 15);
            if (Percent > 100)
            {
                Percent = 100;
            }
            if (Percent < 0)
            {
                Percent = 0;
            }
            if (Percent < 20)
            {
                
            }
        }



        private void DrawSlider(SKCanvas canvas, SKImageInfo info, float percent)
        {
            var y = info.Height - ThumbSize - SelectedThumbThickness; // minus the thumb radius, minus thumb thickness
            percent = Math.Min(percent, 100);
            var selectX = info.Width * percent / 100;

            canvas.DrawLine(0, y, selectX, y, SliderSelectedPaint);
            canvas.DrawLine(selectX, y, info.Width, y, SliderUnSelectedPaint);
        }
    }
}
9jyewag0

9jyewag01#

正如Jason所说,模板化控件中的元素不能被Name引用。
如果你在ListView中的SKCanvasView中添加事件,并在YourPage.xaml.cs中实现这个函数,你可以通过参数sender获得View的示例。
请参考以下代码:

public partial class MainPage : ContentPage 
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void balloon_slider_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
    {
        SKCanvasView  sKCanvasView = (SKCanvasView)sender;
    }
}

更新日期:

一般来说,我们建议使用MVVMdata binding来实现这一点,为了进行比较,我添加了两个按钮,一个使用Command方法响应click事件,另一个添加Clicked事件。
您可以参考以下代码:

我的视图模型.cs

public class MyViewModel
    {
        public ObservableCollection<Item> Items { get; set; }
   
        public ICommand RemoveItemCommand { get; set; }
   
        public MyViewModel() { 
         Items = new ObservableCollection<Item>();

            Items.Add( new Item { NumType = "S" , LocationCode = "0001"});
            Items.Add(new Item { NumType = "M", LocationCode = "0002" });
            Items.Add(new Item { NumType = "L", LocationCode = "0003" });
            Items.Add(new Item { NumType = "S", LocationCode = "0001" });
            Items.Add(new Item { NumType = "M", LocationCode = "0002" });
            Items.Add(new Item { NumType = "L", LocationCode = "0003" });
  

            RemoveItemCommand = new Command<Item>(RemoveItem);
   
        }

        private void RemoveItem(Item obj)
        {
            if (Items != null && Items.Contains(obj))
            {
                Items.Remove(obj);
            }
        }
      
    }

项目.cs

public class Item: INotifyPropertyChanged 
{
    private bool _isChecked;
    public bool IsChecked
    {
        get => _isChecked;
        set
        {
            SetProperty(ref _isChecked, value);
        }
    }

    public string NumType { get; set; }

    public string LocationCode { get; set; }

    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;
}

主页.xaml

<?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:xamlistviewapp131="clr-namespace:XamListViewApp131"
             xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="XamListViewApp131.MainPage"
             >
    <ContentPage.BindingContext>
        <xamlistviewapp131:MyViewModel></xamlistviewapp131:MyViewModel>
    </ContentPage.BindingContext>

        <StackLayout  Orientation="Vertical"
                      Spacing="25"
                      Padding="30,0"
                      VerticalOptions="Center"
                     >

        <ListView Grid.Row="1"  x:Name="listview"   ItemsSource="{Binding Items}"  >
                
                <ListView.Header>TheHeader</ListView.Header>
                
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="70"/>
                                    <ColumnDefinition Width="50"/>
                                    <ColumnDefinition Width="120"/>
                                    <ColumnDefinition Width="80"/>
                                    <ColumnDefinition Width="80"/>
                            </Grid.ColumnDefinitions>

                                <Label Grid.Row="0" Grid.Column="0" Text="{Binding NumType}" Margin="0,0,0,0" />
                                <Label Grid.Row="0" Grid.Column="1" Text="{Binding LocationCode}"  Margin="0,0,0,0" />
  
                            <Button Text="Remove" Grid.Column="2" Command="{Binding BindingContext.RemoveItemCommand, Source={x:Reference listview}}"  CommandParameter="{Binding .}"  />
                            
                            <Button Text="Test" Grid.Column="3" Clicked="Button_Clicked"  CommandParameter="{Binding .}"  />

                            <skia:SKCanvasView x:Name="balloon_slider" Grid.Column="4"   BackgroundColor="Yellow"   WidthRequest="50" HeightRequest="50"
                                             PaintSurface="balloon_slider_PaintSurface" />

                        </Grid>

                    </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>

</ContentPage>

主页.xaml.cs

public partial class MainPage : ContentPage 
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void balloon_slider_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
    {
        SKCanvasView  sKCanvasView = (SKCanvasView)sender;

    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        Button button = (Button)sender;
        Item item= button.CommandParameter as Item;

        System.Diagnostics.Debug.WriteLine("click item is: "+item.NumType);   
    }
}

相关问题