xamarin 对应用程序资源使用绑定上下文

ocebsuys  于 2022-12-20  发布在  其他
关注(0)|答案(2)|浏览(138)

我有一个Xamarin应用程序,它在App.xaml中集中定义了控件的某些属性和样式

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="AppMsMovil.App">
<Application.Resources>
    <ResourceDictionary>
        <Color x:Key="MainColorBlue">#003E62</Color>
        <Color x:Key="MainTextColorBlue">White</Color>
        <Color x:Key="SecondaryColorBlue">#6f95ab</Color>
        <Color x:Key="MainColorRed">#EC1B30</Color>
        <Color x:Key="MainTextColorRed">White</Color>
        <Color x:Key="SecondaryColorRed">#edb2b8</Color>
        <Color x:Key="MainColorGray">#e6e4df</Color>
        <Color x:Key="SelectedItemColor">#f7d6a1</Color>
        <Color x:Key="UnselectedItemColor">White</Color>

        <Color x:Key="CanceledColor">#ffa099</Color>
        <Color x:Key="ClosedColor">#fded98</Color>
        <Color x:Key="SentColor">#a9efbb</Color>

        <Style TargetType="Entry">
            <Setter Property="BackgroundColor" Value="White" />
            <Setter Property="PlaceholderColor" Value="Gray" />
            <Setter Property="TextColor" Value="Black" />
        </Style>
        <Style TargetType="Button">
            <Setter Property="BackgroundColor" Value="{StaticResource MainColorBlue}" />
            <Setter Property="TextColor" Value="White" />
            <Setter Property="CornerRadius" Value="20" />
        </Style>
        <Style TargetType="Label">
            <Setter Property="TextColor" Value="{StaticResource MainColorBlue}" />
        </Style>

        <Style x:Key="DynamicOnDeviceLabelStyle" TargetType="Label" >
            <Setter Property="FontSize" Value="{Binding LcModel.DynamicOnDeviceLabelFontSize}" />
        </Style>

        <Style TargetType="ContentPage" ApplyToDerivedTypes="True">
            <Setter Property="BackgroundColor" Value="{StaticResource MainColorGray}" />
        </Style>

        <Style TargetType="ContentView" ApplyToDerivedTypes="True">
            <Setter Property="BackgroundColor" Value="{StaticResource MainColorGray}" />
        </Style>

        <Style TargetType="Picker">
            <Setter Property="TextColor" Value="Black"></Setter>
            <Setter Property="TitleColor" Value="#7e8185"></Setter>
        </Style>

        <Style TargetType="SearchBar">
            <Setter Property="TextColor" Value="Black"></Setter>
            <Setter Property="BackgroundColor" Value="DarkGray"></Setter>
        </Style>

    </ResourceDictionary>
</Application.Resources>

我正在尝试创建Style以将FontSize属性应用于应用程序内的Labels控件。但是,我希望根据应用程序执行环境确定StyleFontSize的值。(如果是平板电脑,我想要一个大小,如果是手机,我想要另一个)为此,我为App类创建了ModelViewModel类,如下所示。
类:应用程序模型. cs

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace AppMsMovil.Models {
    public class AppModel : INotifyPropertyChanged {

    private double LcDblDynamicOnDeviceLabelFontSize;
        public double DynamicOnDeviceLabelFontSize {
            get => LcDblDynamicOnDeviceLabelFontSize;
            set {
                if (LcDblDynamicOnDeviceLabelFontSize != value) {
                    LcDblDynamicOnDeviceLabelFontSize = value;
                    OnPropertyChanged();
                }
            }
        }

        /// Para actualizar los controles enlazados
        public event PropertyChangedEventHandler PropertyChanged;
        public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

类:应用程序视图模型. cs

using AppMsMovil.Models;
using Xamarin.Forms;

namespace AppMsMovil.ViewModels {
    public class AppViewModel {

        public AppModel LcModel { get; set; }

        public AppViewModel() {
            LcModel = new AppModel();
            SbSetDynamicOnDeviceProperties();
        }

        private void SbSetDynamicOnDeviceProperties() {
            string StrOnDeviceLabelFontSize = Device.Idiom == TargetIdiom.Phone ? "Small" : Device.Idiom == TargetIdiom.Tablet ? "Medium" : "Medium";
            LcModel.DynamicOnDeviceLabelFontSize = (double)new FontSizeConverter().ConvertFromInvariantString(StrOnDeviceLabelFontSize);
        }
    }
}

最后,在App类上,我用一个ViewModel对象设置了BindingContext
类别:应用程序xaml. cs

using Xamarin.Forms;
using AppMsMovil.ViewModels;

namespace AppMsMovil {
    public partial class App : Application {

        public bool IsLoggedIn {
            get {
                return Current.Properties.ContainsKey("IsLoggedIn") && (bool)Current.Properties["IsLoggedIn"];
            }
        }

        public App() {
            InitializeComponent();
            BindingContext = new AppViewModel();
            MainPage = new AppShell();
        }

        protected override void OnStart() {
        }

        protected override void OnSleep() {
            Current.Properties.Remove("IsLoggedIn");
        }

        protected override void OnResume() {
        }            
    }
}

如果我运行应用程序,我可以看到ModelViewModel类已正确创建,但是,在时,我无法看到AppModel. cs类上的DynamicOnDeviceLabelFontSize属性的Get方法已执行。因此,我认为没有为我的Style上的Setter的****Value分配该值。(我确认这一点,因为在XAML文件中,我使用的样式未采用正确的值)
注意:如果我在样式Setter的****值上设置静态值,我可以看到标签控件采用正确的值,因此,这不是样式问题,但似乎Setter的值没有从绑定中取值。
问:是否可以使用绑定应用程序.资源中的样式Setter值上赋值?或者我的操作有误?
欢迎任何支持。
问候!

    • 更新:**使用评论中的想法解决......这是最终解决方案:
<Style x:Key="DynamicOnDeviceLabelStyle" TargetType="Label" >
        <Setter Property="FontSize" Value="{OnIdiom Phone=Small, Tablet=Medium}" />
    </Style>

多谢了!

k2fxgqgv

k2fxgqgv1#

最后回到家里,我想向您展示一些可以使用OnIdiom的很酷的技巧
第一步:在XAML中使用OnIdiom。您可以在视图堆栈中的元素的任何属性上使用OnIdiom。这对于能够根据设备管理不同的值非常有用。

{OnIdiom Phone=Value, Tablet=Value}

第二:还有OnPlatform,这使您能够在不同的平台上做不同的事情。

{OnPlatform Android=Value, iOS=Value}

进一步,您可以合并这2个元素组合在一起,这是组合后的外观

{OnIdiom Phone={OnPlatform Android=Value, iOS=Value}, Tablet={OnPlatform Android=Value, iOS=Value}}

你甚至可以在样式上更进一步,沿着这条线实现一些东西,你将能够确定设备是General Size还是Small Size
App.xaml中,确保将x:Name="dictionary添加到您的主Application.Resources中,否则您将无法在后面的代码中加载自定义dictionaries

<Application.Resources>
    <ResourceDictionary x:Name="dictionary"> <----- IMPORTANT
    </ResourceDictionary>        
</Application.Resources>

App.xaml.cs中,把这个添加到类中,你想确定屏幕大小,所以我们设置了几个const的大小。创建一个IsASmallDevice方法,如果设备很小,则返回true,否则返回false。然后,我们希望通过使用DeviceInfo类并检查我们使用的平台,使用LoadStyles方法加载样式。我们正在努力加载正确的样式。一旦我们理解了一些事情,我们希望通过MergedDictionaries.Add(our instance of ResourceDictionary)将我们的自定义ResourceDictionaryAppResource合并。

public partial class App : Application
{
    const int smallWightResolution = 768;
    const int smallHeightResolution = 1280;

    public App()
    {
        InitializeComponent();
        LoadStyles();

        MainPage = new AppShell();
    }

    void LoadStyles()
    {
        var isSmall = IsASmallDevice();

        if (DeviceInfo.Platform == DevicePlatform.Android)
        {
            if (isSmall)
                dictionary.MergedDictionaries.Add(AndroidSmallDeviceStyles.SharedInstance);
            else
                dictionary.MergedDictionaries.Add(AndroidDeviceStyles.SharedInstance);
        }else if (DeviceInfo.Platform == DevicePlatform.iOS)
        {
            if (isSmall)
                dictionary.MergedDictionaries.Add(iOSSmallDeviceStyles.SharedInstance);
            else
                dictionary.MergedDictionaries.Add(iOSDeviceStyles.SharedInstance);
        }
    }

    public static bool IsASmallDevice()
    {
        var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;

        var width = mainDisplayInfo.Width;

        var height = mainDisplayInfo.Height;
        return (width <= smallWightResolution && height <= smallHeightResolution);
    }
}

接下来你要创建Content Page并像这样修改它。把Content Page变成一个ResourceDictionary,允许你做和AppResourceDictionary相同的事情,但是分开。

<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="Class.Styles.AndroidDeviceStyles">

</ResourceDictionary>

Content Page.xaml.cs中添加此函数以将其启用为ResourceDictionry,并使用static property创建该类的新示例,从而允许您根据加载的设备大小在App中调用它。

public partial class AndroidDeviceStyles : ResourceDictionary
{
    public static AndroidDeviceStyles SharedInstance { get; } = new AndroidDeviceStyles();
    public AndroidDeviceStyles()
    {
        InitializeComponent();
    }
}

在新的ResourceDictionary中,这就是您想要设置新样式的方式。

<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="Class.Styles.AndroidDeviceStyles">
    
    <Style x:Key="Public Key To Access Through Static Resource"
           TargetType="Your Targer Type e.g Grid">
        <Setter Property="WidthRequest"
                Value="100" />
        <Setter Property="HeightRequest"
                Value="100" />
        <Setter Property="BackgroundColor"
                Value="Red" />
    </Style>
    
</ResourceDictionary>

这是我通常做我的,每个平台一个。我发现,它几乎是不可能得到它的权利与一个单一的风格在每个平台之间,所以是的,我知道这可能是很多工作要开始,但一旦它完成了,你会非常高兴自己有这个孩子的分离和控制每一个风格在您的应用程序。

如果你有任何更多的问题,请让我知道在评论中,我会非常乐意向你展示更多,并解释我可能忘记在这个答案中提到的事情。

8hhllhi2

8hhllhi22#

终于找到了解决办法......
model和viewmodel类不是必须的,我只需要修改这一行。
使用评论中的想法解决...这是最终解决方案:

<Style x:Key="DynamicOnDeviceLabelStyle" TargetType="Label" >
    <Setter Property="FontSize" Value="{OnIdiom Phone=Small, Tablet=Medium}" />
</Style>

多谢了!

相关问题