【问题标题】:Is it possible to point one Color resource to another Color resource in Xamarin.Forms?是否可以将一个颜色资源指向 Xamarin.Forms 中的另一个颜色资源?
【发布时间】:2016-01-27 15:53:13
【问题描述】:

我正在构建一个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 你能做到here 所说的答案

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

【问题讨论】:

    标签: c# xamarin xamarin.forms


    【解决方案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】:

      您可以将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>
      

      【讨论】:

      • 这是否意味着您创建了一个新文件 Colors.cs?那么你把它放在哪里,在模型、视图模型、视图或其他地方? TY
      【解决方案3】:

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

      我发现这里真正的问题是我需要“主题化”我的 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.FormsSealed 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 类中的一个 setter 属性如下所示:

      你是说那个值是什么意思?

      这是拼图的最后一块。一种扩展方法,允许您像上面一样定义xaml

      首先是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);
      

      如果有人有更好的样式设计模式我很想听听的应用程序

      【讨论】:

      • 自从MergedDictionaries 被引入Xamarin.Forms 之后,这个方法变得容易多了
      【解决方案4】:

      @Arconox 有正确答案,这里有一些额外的提示。

      public class ReferenceColor
      {
          public Color Color { get; set; }
      
          public ReferenceColor()
          {
      
          }
      
          public static implicit operator Color(ReferenceColor referenceColor) => referenceColor.Color;
      }
      

      是我用来让自己在运行时为我的 Xamarin.Forms 应用程序设置主题的代码。因此,就 Arconox 而言,除非您在应用程序运行后更改主题/颜色,否则不需要 INotifyPropertyChanged。这允许这样的用例。

      <Color x:Key="Merlot">#750411</Color>
      <local:ReferenceColor x:Key="Page.Static.Background" Color="{StaticResource Merlot}"/>
      <Grid BackgroundColor="{DynamicResource Page.Static.Background}">
      </Grid>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-15
        • 1970-01-01
        • 2011-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-31
        相关资源
        最近更新 更多