是否可以将一个Color资源指向Xamarin.Forms中的另一个Color资源?

时间:2016-01-27 15:53:13

标签: c# xamarin xamarin.forms

我正在构建一个Xamarin Forms应用程序,我目前正在绘制我的应用程序Resources,主要是我的颜色。

例如,我有以下内容:

  <Color x:Key="Slate">#404040</Color>
  <Color x:Key="Blue">#458623</Color>

  <Color x:Key="SelectedItemColour">#458623</Color>

您可以看到我的SelectedItemColourBlue相同。

我尝试过以下但是没有用:

  <Color x:Key="Slate">#404040</Color>
  <Color x:Key="Blue">#458623</Color>

  <Color x:Key="SelectedItemColour" Color="{StaticResource Blue}"/>

我知道如果WPF你可以做出pop-it

所说的答案

是否可以在Xamarin.Forms中将Colour Resource指向另一个Colour Resource

3 个答案:

答案 0 :(得分:3)

您可以将x:Static与静态类结合使用,以便按名称直接引用这些颜色。这样做的好处是可以将颜色集中在一个类中,并最大限度地减少XAML的数量。

namespace ResourceColors
{
    public static class Colors
    {
        public static Color Slate = Color.FromHex("#404040");
    }
}


<?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:local="clr-namespace:ResourceColors;assembly=ResourceColors" x:Class="ResourceColors.PageOne">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Color x:Key="Blue">#458623</Color>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
            <Label Text="Test" TextColor="{x:Static local:Colors.Slate}" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

答案 1 :(得分:1)

这可能是个老问题,但是我今天试图在一个项目中完成同样的事情,并且想要一个比这里提出的解决方案更优雅的解决方案。似乎没有一种方法可以完全使用XAML来完成,但这是我最终使用的解决方案。

首先,我定义了一个名为ColorReference的实用程序类:

public class ColorReference : INotifyPropertyChanged
{
    private Color color = Color.Black;

    public Color Color
    {
        get => this.color;
        set
        {
            this.color = value;
            this.OnPropertyChanged();
        }
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

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

    #endregion

    public static implicit operator Color(ColorReference colorReference) => colorReference.Color;
}

我不是100%肯定需要实施INotifyPropertyChanged,但我认为这样做不会造成伤害(可能允许在运行时更改颜色;我尚未对此进行测试)。

要使用它,只需将其用作ResourceDictionary中的资源:

<Color x:Key="FirstColor">#51688f</Color>
...
<utility:ColorReference x:Key="SomeOtherColorName" Color="{StaticResource FirstColor}" />

在我的用例中,我使用它来设置主题中定义的颜色的Telerik控件样式,这样,如果我创建一个新主题,则无需在整个地方复制相同的颜色值。明显的缺点是,对于Color以外的任何类型,都需要定义一个新类,但我怀疑我是否需要太多类型来像这样别名。希望这可以在将来帮助其他人尝试做与我相同的事情。

答案 2 :(得分:0)

所以我必须这样做非常复杂,所以请仔细聆听。

我发现这里真正的问题是我需要“主题化”我的Xamarin.Forms应用程序。

所以我做了什么。

首先成为abstract Theme班级:

public abstract class Theme
{
    public Dictionary<string, Color> Colours { get; set; } = new Dictionary<string, Color>();

    protected void DictionaryThemes(Type type)
    {
        var properties = type.GetRuntimeProperties();
        foreach (PropertyInfo propInfo in properties)
        {
            if (propInfo.PropertyType == typeof(Color))
            {
                var key = propInfo.Name;
                var value = propInfo.GetValue(this);
                Colours.Add(key, (Color)value); 
            }
        }
    }

    public abstract Color TitleColour { get; }
}

使用反射来填充我的Resources

字典的好方法

然后我用我的实际主题扩展了这个类:

public class MyTheme : Theme
{
    public MyTheme()
    {
        DictionaryThemes(typeof(MyTheme));
    }

    //Slate
    public override Color TitleColour { get; } = Color.FromHex("#00ff00");
}

还在我身边吗?良好...

然后,我必须将此主题加载到我的Application Resources中,并将其与我的其他应用程序资源合并。我必须将MyTheme资源与其他Resources分开,以便稍后我可以在我的主Resources文件中使用它。

让我告诉你,这是我的CurrentTheme资源文件:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:styling="clr-MyApp.Styling;assembly=MyApp"
             x:Class="MyApp.Styling.CurrentTheme">
  <ContentPage.Resources>
    <ResourceDictionary>
  <styling:MyTheme x:Key="CurrentTheme"/>
</ResourceDictionary>

我必须将其作为页面的一部分来执行,因为Xamarin.Forms Sealed ResourceDictionary(see here)意味着您无法扩展它并创建自己的类CurrentTheme耻辱。无论如何我离题了。

然后我将我的应用程序资源设置为 var currentTheme = new CurrentTheme(); Xamarin.Forms.Application.Current.Resources = currentTheme.Resources; ,如下所示:

Resource

然后我可以在我的主Styles文件中合并其他样式,在本例中称为<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:styling="clr-MyApp.Styling;assembly=MyApp" x:Class="MyApp.Styling.Styles"> <ContentPage.Resources> <ResourceDictionary> <Style x:Key="TitleStyle" TargetType="Label"> <Setter Property="FontAttributes" Value="Bold" /> <Setter Property="FontSize" Value="30" /> <Setter Property="TextColor" Value="{styling:Colour TitleColour}" /> </Style> </ResourceDictionary>

 var styles = new Styles();
 foreach (var item in styles.Resources)
 {
       Application.Current.Resources.Add(item.Key,item.Value);
 }

我将其合并到我的主要应用程序资源中,如下所示:

Styles

现在您可以看到xaml类中的一个setter属性如下所示:

你说的是什么意思?

这是拼图的最后一部分。一种扩展方法,可让您像上面一样定义ColourExtension

首先是// You exclude the 'Extension' suffix when using in Xaml markup [ContentProperty("Text")] public class ColourExtension : IMarkupExtension { public string Text { get; set; } public object ProvideValue(IServiceProvider serviceProvider) { if (Text == null) throw new Exception("No Colour Key Provided"); return StylingLookup.GetColour(Text); } } 类:

StylingLookup

最后是public static class StylingLookup { public static Color GetColour(string key) { var currentTheme = (Application.Current.Resources["CurrentTheme"] as Theme); return currentTheme.Colours[key]; } } 类:

CurrentTheme

现在一切都有道理,为什么我们必须从主Styles资源中分割var currentTheme = (Application.Current.Resources["CurrentTheme"] as Theme); 。由于行:

#include <iostream>

struct O
{
   const int id;
   O(int x) : id(x) {}
};

O* global = nullptr;

void externalFunc() {
    global->~O();
    new(global) O(42);
}

int func(O* o)
{
    int first = o->id;
    externalFunc();
    // o->id has changed, even though o hasn't    
    return o->id + first;
}

int main()
{
    O o(1);
    global = &o;
    std::cout << func(&o);
}

如果有人有更好的样式模式,我很乐意听到它