Есть ли какой-либо способ отделить стиль от моего XAML в Xamarin.Формы

#c# #xaml #xamarin #xamarin.forms

#c# #xaml #xamarin #xamarin.forms

Вопрос:

Я использую Xamarin.Формы в PCL со страницами XAML. Единственный способ, который я придумал для оформления своих элементов управления, — это использовать встроенный синтаксис.

 <Button Text="Inquiry" TextColor="Blue" />
  

Я бы предпочел использовать структуру, подобную этой:

 <Page.Resources>
    <Style TargetType="Button">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Foreground" Value="Blue" />
    </Style>
</Page.Resources>
  

(http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465381.aspx )

Однако элемент Style (пока) не поддерживается. Кому-нибудь удалось отделить макет от содержимого?

К вашему сведению: я также опубликовал этот вопрос на форумах Xamarin, поэтому любой, кто попал сюда с помощью Google, возможно, захочет также проверить эту страницу: http://forums.xamarin.com/discussion/19287/styling-of-xamarin-xaml#latest

Ответ №1:

Стиль не такой сложный [требуется цитирование]. Вы можете реализовать свой собственный, как я только что сделал для целей этого ответа.

Вот как будет выглядеть Xaml:

 <ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:YourNS;assembly=YourAssembly">
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:Style x:Key="buttonStyle">
                <local:Setter Property="BorderWidth" Value="5"/>
            </local:Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <Button Text="Foo" local:Style.Style="{StaticResource buttonStyle}" x:Name="button"/>
</ContentPage>
  

вспомогательный код будет выглядеть так:

 namespace YourNS
{

    public class Setter {
        public string Property { get; set; }
        public string Value { get; set; }
    }

    [ContentProperty ("Children")]
    public class Style
    {
        public Style ()
        {
            Children = new List<Setter> ();
        }

        public IList<Setter> Children { get; private set; }

        public static readonly BindableProperty StyleProperty = 
            BindableProperty.CreateAttached<Style, Style> (bindable => GetStyle (bindable), default(Style), 
                propertyChanged: (bindable, oldvalue, newvalue)=>{
                    foreach (var setter in newvalue.Children) {
                        var pinfo = bindable.GetType().GetRuntimeProperty (setter.Property);
                        pinfo.SetMethod.Invoke (bindable,new [] {Convert.ChangeType (setter.Value, pinfo.PropertyType.GetTypeInfo())});
                    }

                });

        public static Style GetStyle (BindableObject bindable)
        {
            return (Style)bindable.GetValue (StyleProperty);
        }

        public static void SetStyle (BindableObject bindable, Style value)
        {
            bindable.SetValue (StyleProperty, value);
        }
    }
}
  

Очевидно, что код, выполняющий назначение, очень легкий, и вам, возможно, придется адаптировать его к вашим потребностям (поддержка перечислений и т. Д.), Но Он работает в этом упрощенном случае.

Я уверен, что это поможет.

Комментарии:

1. похоже, это большой шаг в правильном направлении. Единственное, чего мне все еще не хватает, это то, что мне все еще нужно назначить стиль каждому элементу управления. Есть ли у вас какие-либо идеи о том, как реализовать свойство ‘TargetType’?

2. TargetType — это не то, что делает стиль неявным в WPF / SL. Отсутствие x:Key есть. Вы можете очень легко реализовать TargetType, что добавит проверку, чтобы избежать поиска свойств для элементов, которых не существует, но сейчас вы не найдете способа установить неявный стиль для Xamarin. Элементы управления формами, за исключением случаев, когда вы создаете подкласс для каждого типа.

3. Для оформления LayoutOptions и других свойств с помощью преобразователей типов это помогло мне: var converterInfo = pInfo.PropertyType.GetCustomAttribute<TypeConverterAttribute>(); if (converterInfo != null) { var converterType = Type.GetType(converterInfo.ConverterTypeName); var conv = (TypeConverter)Activator.CreateInstance(converterType); return conv.ConvertFrom(value); }

4. Я получаю эту ошибку, используя вышеупомянутый код «Ошибка CS0029: не удается неявно преобразовать тип NS.LeftMenu.Style' to TPropertyType’ (CS0029) (NS)»

5. @NiravMehta столкновение пространств имен. либо переименуйте стиль во что-то другое, либо предоставьте полное пространство имен для типов

Ответ №2:

Теперь доступна поддержка стилей:

 <ContentPage.Resources>
   <ResourceDictionary>

  <Style TargetType="Label">
    <Setter Property="HorizontalOptions" Value="LayoutOptions.Center" />
    <Setter Property="VerticalOptions" Value="LayoutOptions.Center" />
    <Setter Property="FontSize" Value="48" />
    <Setter Property="FontAttributes" Value="Bold, Italic" />
    <Setter Property="Opacity" Value=".5" />
    <Setter Property="TextColor" Value="Black" />
    <Setter Property="Text" Value="Copied" />
    <Setter Property="IsVisible" Value="False" />
  </Style>

  </ResourceDictionary>
</ContentPage.Resources>
  

Комментарии:

1. Я создаю макет без использования XAML. Как я могу использовать этот стиль, используя только код?

Ответ №3:

Из Xamarin.В формах 1.3 вы получаете больше вариантов стиля.

Xamarin.Предварительный просмотр технологии Forms 1.3

  • Поддержка стилей в XAML и в коде
  • Разрешить стили на основе DynamicResources через Style .BaseResourceKey
  • Добавьте стили, зависящие от платформы, через устройство.Стили (поддерживает динамический тип iOS)

Ответ №4:

Я смог создать код, который ближе к ResourceDictionary, к которому я больше привык в WPF / Silverlight, и удалить его с фактической страницы (просмотра)

  1. Вместо того, чтобы иметь только App.cs, я создал новый файл xaml.. App.xaml вместе с сопутствующим кодом App.xaml.cs. Я взял то, что было в App.cs, и поместил его в App.xaml.cs.

     public partial class App : Application
    {
        public App()
        {
           var _mainView = new MainView();
           var _navPage = new NavigationPage(_mainView);
           MainPage = _navPage;
        }
    
       //.. the methods below are currently empty on mine, 
       //still figuring out some of the front end ..
       protected override void OnStart(){ }
       protected override void OnSleep(){ }
       protected override void OnResume(){ }    
      

    }

  2. Это позволило мне в App.xaml объявлять ресурсы приложения, которые я могу использовать в других представлениях:

         <Style x:Key="buttonStyle" TargetType="{x:Type Button}">
            <Setter Property="TextColor" Value="Blue"/>
            <!-- note: I tried Foreground and got errors, but once I 
                 used TextColor as the property, it ran fine and the 
                 text of the button I had changed color to what I expected -->
            <Setter Property="BackgroundColor" Value="White"/>
            <!-- note: I tried Background and got errors, but once I 
                 used BackgroundColor as the property, it ran fine and the 
                 background of the button I had changed color -->
        </Style>
    
    </ResourceDictionary>
      

И затем я смог использовать стиль на своих страницах, используя StaticResource

 <Button Text="Inquiry" Style="{StaticResource buttonStyle}"/>
  

Вероятно, есть десятки способов, может быть, даже лучше, но это помогло мне сохранить все мои стили в одном месте (App.xaml)

PS Я не знаю, почему он не форматирует пример codebehind, я пробовал несколько раз, но, надеюсь, вы все еще понимаете это.

Комментарии:

1. Можем ли мы сослаться на ButtonStyle, созданный в приведенном выше коде, чтобы задать стиль для кнопки в файле example.cs.

Ответ №5:

Я сам рассматриваю эту проблему с помощью Xamarin Forms, будучи разработчиком Silverlight.

Необязательным подходом было бы создать свои собственные элементы управления («Представления» в терминах Xamarin) либо в XAML, либо в коде, и использовать их при создании вашего интерфейса.