.NET MAUI ContentView 中属性值和绑定的更新

huangapple go评论63阅读模式
英文:

Updating of property values & bindings in .NET MAUI ContentView

问题

以下是您提供的文本的翻译部分:

"I'm attempting to try my hand at creating a card-based UI similar to Android's CardView layout using MAUI ContentView. The exemplary use case for such an element is the display of testing or scoring results, so I attempted to roll in some of the underlying logic directly into the new element - the user would simply have to supply an Attempted and a Possible set of integers, i.e. 92 and 100, from which it would display an "out-of" format of 92/100 as well as a percentage of 92.0%.

The issue is that I've tried a number of ways to do this, and none successfully update the Score and Percentage properties correctly. I realize that it may be an issue with the order (or simultaneity) of the properties being set, but I haven't been able to rectify it using BindableProperty.Create(..., propertyChanged:) or other methods."

如果您需要更多帮助或有其他问题,请随时提出。

英文:

I'm attempting to try my hand at creating a card-based UI similar to Android's CardView layout using MAUI ContentView. The exemplary use case for such an element is the display of testing or scoring results, so I attempted to roll in some of the underlying logic directly into the new element - the user would simply have to supply an Attempted and a Possible set of integers, i.e. 92 and 100, from which it would display an "out-of" format of 92/100 as well as a percentage of 92.0%.

The issue is that I've tried a number of ways to do this, and none successfully update the Score and Percentage properties correctly. I realize that it may be an issue with the order (or simultaneity) of the properties being set, but I haven't been able to rectify it using BindableProperty.Create(..., propertyChanged:) or other methods.

ProgressViewCard.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView x:Name="this"
             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ExampleApp.Controls.ProgressCardView">
    <Frame BindingContext="{x:Reference this}" BackgroundColor="{Binding BackgroundColor}" CornerRadius="5" HasShadow="True">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="3*"   />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="2*"   />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="10*" />
                <ColumnDefinition Width="4*"  />
                <ColumnDefinition Width="4*"  />
            </Grid.ColumnDefinitions>

            <!-- Configure the button functionality of the ProgressCardView -->
            <Button x:Name="InternalButton" Grid.RowSpan="3" Grid.ColumnSpan="2" Opacity="0.0" Clicked="buttonEvent" />

            <Label Text="{Binding Title}" HorizontalOptions="Start" VerticalOptions="Center" FontSize="17" TextColor="{Binding HeaderColor}" />
            <Label Text="{Binding Score}" Grid.Column="1" Grid.ColumnSpan="2" HorizontalOptions="End" VerticalOptions="Center" FontSize="12" TextColor="{Binding TextColor}" />
            <BoxView Grid.Row="1" Grid.ColumnSpan="3" HeightRequest="1" Color="{Binding TextColor}"/>
            <ProgressBar x:Name="CardProgressBar" Grid.Row="2" Grid.ColumnSpan="2" />
            <Label Text="{Binding Percentage}" Grid.Row="2" Grid.Column="2" HorizontalOptions="End" VerticalOptions="Center" FontSize="12" TextColor="{Binding TextColor}" />
        </Grid>
    </Frame>
</ContentView>

ProgressViewCard.xaml.cs:

namespace ExampleApp.Controls
{
    public partial class ProgressCardView : ContentView
    {
        private int attempted  = 0;
        private int possible   = 0;

        #region BindableProperties

        public static readonly BindableProperty TitleProperty = BindableProperty.Create(
			nameof(Title), 
			typeof(string), 
			typeof(ProgressCardView2), 
			string.Empty);

        public static readonly BindableProperty AttemptedProperty = BindableProperty.Create(
            nameof(Attempted),
            typeof(int),
            typeof(ProgressCardView2),
            0);

        public static readonly BindableProperty PossibleProperty = BindableProperty.Create(
            nameof(Possible),
            typeof(int),
            typeof(ProgressCardView2),
            1);

        public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create(
			nameof(BackgroundColor), 
			typeof(Color), 
			typeof(ProgressCardView2), 
			Color.FromArgb("#FFFFFF"));

		public static readonly BindableProperty HeaderColorProperty = BindableProperty.Create(
			nameof(HeaderColor), 
			typeof(Color), 
			typeof(ProgressCardView2), 
			Color.FromArgb("#FFFFFF"));

        public static readonly BindableProperty TextColorProperty = BindableProperty.Create(
			nameof(TextColor), 
			typeof(Color), 
			typeof(ProgressCardView2), 
			Color.FromArgb("#FFFFFF"));

        #endregion

        #region Getters and Setters

        public string Title 
        {
            get => (string) GetValue(ProgressCardView2.TitleProperty);
            set => SetValue(ProgressCardView2.TitleProperty, value);
        }

        public int Attempted
        {
            get => (int) GetValue(ProgressCardView2.AttemptedProperty);
            set => SetValue(ProgressCardView2.AttemptedProperty, value);
        }

        public int Possible
        {
            get => (int)GetValue(ProgressCardView2.PossibleProperty);
            set => SetValue(ProgressCardView2.PossibleProperty, value);
        }

        public string Score
        {
            get { return String.Format("{0}/{1}", this.attempted, this.possible); }
            set { this.Score = value; }
        }

        public string Percentage
        {
            get { return String.Format("{0:P1}", ((double) this.attempted) / ((double) this.possible)); }
            set { this.Score = value; }
        }

        public Color BackgroundColor
    	{
        	get => (Color) GetValue(ProgressCardView2.BackgroundColorProperty);
        	set => SetValue(ProgressCardView2.BackgroundColorProperty, value);
    	}

		public Color HeaderColor
    	{
        	get => (Color) GetValue(ProgressCardView2.HeaderColorProperty);
        	set => SetValue(ProgressCardView2.HeaderColorProperty, value);
    	}

        public Color TextColor
    	{
        	get => (Color) GetValue(ProgressCardView2.TextColorProperty);
        	set => SetValue(ProgressCardView2.TextColorProperty, value);
    	}

        #endregion

        #region Methods and Events

        public ProgressCardView2()
		{
			InitializeComponent();
        }

		private void buttonEvent(object sender, EventArgs e)
		{

		}

        #endregion
    }
}

The usage of the controls is as follows:

<ctrls:ProgressCardView Title="CS 101 Final"   Attempted="92" Possible="100" BackgroundColor="#ffffff" 
                        HeaderColor="#e74c3c" TextColor="#7f8c8d" />
<ctrls:ProgressCardView Title="ME 302 Midterm" Attempted="68" Possible="85"  BackgroundColor="#ffffff" 
                        HeaderColor="#e74c3c" TextColor="#7f8c8d" />

.NET MAUI ContentView 中属性值和绑定的更新

This is the result in an Android emulator (API 31). How do I modify the above control to obtain the correct behavior?

答案1

得分: 3

你已经完成了大部分工作。我尝试了你的代码并进行了一些修改,这些修改对我有效。

首先,在自定义控件ProgressCardView中,删除前两行:

private int attempted = 0;
private int possible = 0;

因为这与BindableProperty无关,你可以在BindableProperty.Create中设置默认值,这将导致值始终为0。你可以在BindableProperty.Create中设置默认值。

public string Score
{
    get { return String.Format("{0}/{1}", this.attempted, this.possible); } 
}

其次,在BindableProperty中,你可以定义propertyChanged事件处理程序,用于在属性更改时定义回调方法。有关更多信息,你可以参考检测属性更改

对于你的情况,AttemptedPropertyPossibleProperty的更改会导致结果发生更改,因此我们可以将propertyChanged添加到这两个BindableProperty中,如下所示:

public static readonly BindableProperty AttemptedProperty = BindableProperty.Create(
    nameof(Attempted),
    typeof(int),
    typeof(ProgressViewCard),
    0,
    propertyChanged: OnThisPropertyChanged);

public static readonly BindableProperty PossibleProperty = BindableProperty.Create(
    nameof(Possible),
    typeof(int),
    typeof(ProgressViewCard),
    1,
    propertyChanged: OnThisPropertyChanged);

为方便起见,我认为这两个属性可以共享相同的propertyChanged回调方法,用于计算值。

然后,我们可以实现OnThisPropertyChanged回调方法:

private static void OnThisPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    var myCard = bindable as ProgressViewCard;
    myCard.OnPropertyChanged(nameof(Score));
    myCard.OnPropertyChanged(nameof(Percentage));
}

以下是对我有效的ProgressViewCard.cs的完整代码:

// 代码部分不予翻译

希望这对你有用。

英文:

You have done most of the work. I tried your code and made some changes which worked for me.

First, in Custom control ProgressCardView, delete this first two lines:

private int attempted  = 0;
private int possible   = 0;

because this has nothing to do with the BindableProperty and you use the following code which will cause the value always be 0. You could set default value in BindableProperty.Create.

public string Score
{
    get { return String.Format("{0}/{1}", this.attempted, this.possible); } 
}

Second, in BindableProperty, you could define propertyChanged event handler, which could define a callback method when property changed. For more info, you could refer to Detect property changes

And for your case, the change of AttemptedProperty and PossibleProperty would cause the result changed, so we could add propertyChanged to these two BindableProperty. Such like the following:

public static readonly BindableProperty AttemptedProperty = BindableProperty.Create(
    nameof(Attempted),
    typeof(int),
    typeof(ProgressViewCard),
    0,
    propertyChanged:OnThisPropertyChanged);

public static readonly BindableProperty PossibleProperty = BindableProperty.Create(
    nameof(Possible),
    typeof(int),
    typeof(ProgressViewCard),
    1,
    propertyChanged:OnThisPropertyChanged);

For convenience, I think these two properties could share the same propertyChanged callback method, that's to count the value.

Then we could implement the OnThisPropertyChanged callback method:

private static void OnThisPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    var myCard = bindable as ProgressViewCard;
    myCard.OnPropertyChanged(nameof(Score));
    myCard.OnPropertyChanged(nameof(Percentage));
}

Here is the complete code for ProgressViewCard.cs which worked for me:

#region BindableProperties

public static readonly BindableProperty TitleProperty = BindableProperty.Create(
    nameof(Title),
    typeof(string),
    typeof(ProgressViewCard),
    string.Empty);

public static readonly BindableProperty AttemptedProperty = BindableProperty.Create(
    nameof(Attempted),
    typeof(int),
    typeof(ProgressViewCard),
    0,
    propertyChanged:OnThisPropertyChanged);

public static readonly BindableProperty PossibleProperty = BindableProperty.Create(
    nameof(Possible),
    typeof(int),
    typeof(ProgressViewCard),
    1,
    propertyChanged:OnThisPropertyChanged);

private static void OnThisPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    var a = bindable as ProgressViewCard;
    a.OnPropertyChanged(nameof(Score));
    a.OnPropertyChanged(nameof(Percentage));
}


public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create(
    nameof(BackgroundColor),
    typeof(Color),
    typeof(ProgressViewCard),
    Color.FromArgb("#FFFFFF"));

public static readonly BindableProperty HeaderColorProperty = BindableProperty.Create(
    nameof(HeaderColor),
    typeof(Color),
    typeof(ProgressViewCard),
    Color.FromArgb("#FFFFFF"));

public static readonly BindableProperty TextColorProperty = BindableProperty.Create(
    nameof(TextColor),
    typeof(Color),
    typeof(ProgressViewCard),
    Color.FromArgb("#FFFFFF"));

#endregion

#region Getters and Setters

public string Title
{
    get => (string)GetValue(ProgressViewCard.TitleProperty);
    set => SetValue(ProgressViewCard.TitleProperty, value);
}

public int Attempted
{
    get => (int)GetValue(ProgressViewCard.AttemptedProperty);
    set => SetValue(ProgressViewCard.AttemptedProperty, value);
}

public int Possible
{
    get => (int)GetValue(ProgressViewCard.PossibleProperty);
    set => SetValue(ProgressViewCard.PossibleProperty, value);
}

public string Score
{
    get { return String.Format("{0}/{1}", this.Attempted, this.Possible); }
    set { this.Score = value; }
}

public string Percentage
{
    get { return String.Format("{0:P1}", ((double)this.Attempted) / ((double)this.Possible)); }
    set { this.Score = value; }
}

public Color BackgroundColor
{
    get => (Color)GetValue(ProgressViewCard.BackgroundColorProperty);
    set => SetValue(ProgressViewCard.BackgroundColorProperty, value);
}

public Color HeaderColor
{
    get => (Color)GetValue(ProgressViewCard.HeaderColorProperty);
    set => SetValue(ProgressViewCard.HeaderColorProperty, value);
}

public Color TextColor
{
    get => (Color)GetValue(ProgressViewCard.TextColorProperty);
    set => SetValue(ProgressViewCard.TextColorProperty, value);
}

#endregion

#region Methods and Events

public ProgressViewCard()
{
    InitializeComponent();
}

private void buttonEvent(object sender, EventArgs e)
{

}

#endregion

Hope it works for you.

答案2

得分: 2

只需在set方法中添加OnPropertyChanged行,即可使用更少的编码,无需使用propertyChanged方法:

public int Possible
{
    get => (int)GetValue(ProgressCardView2.PossibleProperty);
    set {
        if (SetValue(ProgressCardView2.PossibleProperty, value)) {
            OnPropertyChanged(nameof(Score));
            OnPropertyChanged(nameof(Percentage));
        }
    }
}

对于Attempted重复相同的操作。

这两种方法都可以正常工作。

英文:

An alternative with less coding. Don't need propertyChanged methods.

Just add OnPropertyChanged lines to the set methods:

public int Possible
{
	get => (int)GetValue(ProgressCardView2.PossibleProperty);
	set {
		if (SetValue(ProgressCardView2.PossibleProperty, value)) {
			OnPropertyChanged(nameof(Score));
			OnPropertyChanged(nameof(Percentage));
		}
	}
}

Repeat for Attempted.

Either approach works fine.

huangapple
  • 本文由 发表于 2023年2月19日 22:15:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75500742.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定