Live2D 看板娘 / Demo

Avalonia 学习之 绑定

绑定是一个非常强大的概念,它允许绑定两个属性,这样当其中一个属性发生变化时,另一个也会发生变化。
通常,绑定从source属性到target属性——正常OneWay绑定,但也有一个TwoWay绑定可以确保两个属性同步,无论哪个发生变化。还有另外两种绑定模式:OneWayToSourceOneTime使用频率较低的绑定。

也很少讨论,但同样重要的集合绑定,其中一个集合模仿另一个集合,或者两个集合互相模仿。

请注意,绑定的目标不必与绑定的源完全相同,可以在源和目标之间进行转换,反之亦然。

Avalonia绑定概念

  1. 绑定源对象——通过该对象可以获得绑定源属性的路径。

  2. 绑定目标对象——其AvaloniaProperty(附加、样式或直接)属性用作绑定目标的对象。目标对象只能是派生自AvaloniaObject(这意味着它可以是任何Avalonia视觉对象)的类。AvaloniaObject类似于WPF的DependencyObject

  3. 绑定路径——从源对象到源属性的路径。Path由路径链接组成,每个链接都可以是常规(C#)属性或Avalonia属性。在XAML绑定中,Avalonia属性应放在括号中。下面是XAML中绑定路径的示例:MyProp1.(local:AttachedProperties.AttachedProperty1).MyProp2。此路径意味着在源对象上查找常规C# MyProp1属性,然后在第一个链接返回的对象中查找附加属性AttachedProperty1(在本地命名空间的AttachedProperties类中定义),然后在该附加属性值中查找常规C# MyProp2属性。

  4. Target属性——只能是Attached、StyleDirect Property类型之一。

  5. BindingMode可以:

    1. OneWay——从源头到目标
    2. TwoWay——当源或目标发生变化时,另一个也将得到更新。
    3. OneWayToSource——当目标更新时,源也会更新,但反之则不然。
    4. OneTime——仅在初始化期间从源同步目标一次。
    5. Default——依赖于目标属性的首选绑定模式。初始化Attached Style或Direct Property时,可以指定首选绑定模式,在这种情况下将使用该模式(在绑定本身内未指定BindingMode时)。
  6. 转换器——仅当源值和目标值不同时才需要。它用于将值从源转换为目标,反之亦然。对于通常的绑定,转换器应该实现IValueConverter接口。

不同的绑定源

image

字符串格式化

<TextBlock Text="{Binding FloatValue, StringFormat={}{0:0.0}}" />
<TextBlock Text="{Binding FloatValue, StringFormat=\{0:0.0\}}" />
<TextBlock Text="{Binding FloatValue, StringFormat='{}{0:0.0}'}" />
<TextBlock Text="{Binding MyText,StringFormat='后台值{0}'}" />

绑定转换器

转换器要实现IValueConverter接口,通过Convert(...)ConvertBack(...) 方法定义了绑定源到绑定目标绑定目标到绑定源的转换
我在这里定义一个字符的转换器

using Avalonia.Data;
using Avalonia.Data.Converters;
using System;
using System.Globalization;

namespace BindDemo.Converters
{
    public class TextCaseConverter : IValueConverter
    {

        public object? Convert (object? value, Type targetType, object? parameter, CultureInfo culture)
        {
            if (value is string sourceText && parameter is string targetCase
             && targetType.IsAssignableTo(typeof(string)))
            {
                switch (targetCase)
                {
                    case "upper":
                    case "SQL":
                        return sourceText.ToUpper();
                    case "lower":
                        return sourceText.ToLower();
                    case "title": // Every First Letter Uppercase
                        var txtinfo = new System.Globalization.CultureInfo("en-US", false).TextInfo;
                        return txtinfo.ToTitleCase(sourceText);
                    default:
                        // invalid option, return the exception below
                        break;
                }
            }
            // converter used for the wrong type
            return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
        }

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

使用的时候首选要引用对应的命名空间

xmlns:c="clr-namespace:BindDemo.Converters"

引入资源,定义一个Key

<Window.Resources>
	<c:TextCaseConverter x:Key="textCaseConverter" />
</Window.Resources>

在Bind后面加上转换器

<TextBlock Text="{Binding MyText, 
                  Converter={StaticResource textCaseConverter},ConverterParameter=lower}" />

这样就相当于TextBlock的Text绑定到了ViewModel中的MyText属性,每次MyText(绑定源) 变化时,都会通知到TextBlock,显示的时候呢,会经过textCaseConverterConvert 方法进行转换。

那如果绑定到TextBox时,这边也输入会怎么样呢? 它会进入TextCaseConverterConvertBack方法里。 由于里面直接抛出异常,所以我们可以指定绑定方式为OneWay,完整写法如下

<TextBox Text="{Binding MyText,Mode=OneWay, 
                Converter={StaticResource textCaseConverter}, ConverterParameter=lower}" />

图片路径转换

这个其实挺常用的,绑定图片Source的时候,直接给个字符串的地址是不行的,因为他要求是个Bitmap的类型,那么我们就需要实现一个转换器

using System;
using System.Globalization;
using Avalonia;
using Avalonia.Data.Converters;
using Avalonia.Media.Imaging;
using Avalonia.Platform;

namespace UserControlDemo.Convers
{
    public class StringToImageSourceConverter : IValueConverter
    {
        #region Converter

        private IAssetLoader _assetLoader;

        public StringToImageSourceConverter()
        {
            _assetLoader = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                string path = (string)value;
                return new Bitmap(_assetLoader.Open(new Uri("avares://UserControlDemo/Assets/" + path)));
            }
            catch (Exception e)
            {
                return null;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }

        #endregion
    }
}

视图上绑定这样写

<Style Selector="StackPanel > Image">
            <Setter Property="Source" Value="{Binding #Uc.MenuImg, Converter={StaticResource ToImage}}" />
        </Style>

我为什么要把这个单独拉出来说呢。。。因为我在这里踩过一个坑
image
转换器中Bitmap引入类型一定要是 Avalonia.Media.Imaging,希望你不像我一样马虎  ̄□ ̄||

以上代码示例地址
https://gitee.com/CRole/my-avalonia-demo

posted @ 2023-04-18 15:48  MChuang  阅读(1551)  评论(0编辑  收藏  举报