Как это выглядит сейчас: Превью. Мне нужно изменить Label.TextColor, когда длина Entry.Text будет равна Entry.MaxLength. У меня также есть файл MyEntry.cs с классом MyEntry. Вот мой код:
<ControlTemplate x:Key = "MyEntryTemplate">
<Frame
Padding = "7"
CornerRadius = "25"
BorderColor = "{TemplateBinding BorderColor}">
<Frame.Resources>
<controls:EntryTextConverter
Element = "{Binding Source = {x:Reference entry}}"
x:Key = "TextToIntConverter" />
</Frame.Resources>
<VerticalStackLayout>
<Entry
x:Name = "entry"
FontSize = "{TemplateBinding EntryFontSize}"
Margin = "2"
MaxLength = "{TemplateBinding EntryLength}" />
<Label HorizontalOptions = "End" >
<Label.Text>
<Binding Source = "{x:Reference entry}" Path = "Text"
Converter = "{StaticResource TextToIntConverter}" />
</Label.Text>
<Label.Triggers>
<DataTrigger TargetType = "{x:Type Label}"
Binding = "{Binding Source = {x:Reference entry}, Path=Text.Length}"
Value = "{TemplateBinding EntryLength}">
<Setter Property = "TextColor" Value = "Red"/>
<Setter Property = "FontAttributes" Value = "Bold"/>
</DataTrigger>
</Label.Triggers>
</Label>
</VerticalStackLayout>
</Frame>
</ControlTemplate>
<controls:MyEntry
Margin = "20"
EntryFontSize = "25"
BorderColor = "Black"
EntryLength = "30"
ControlTemplate = "{x:StaticResource MyEntryTemplate}"/>
Вы утверждаете, что хотите, чтобы это было сделано с помощью MVVM, но при этом делаете все возможное, чтобы сломать эту архитектуру.
Правда в том, что этот триггер данных:
<DataTrigger TargetType = "{x:Type Label}"
Binding = "{Binding Source = {x:Reference entry}, Path=Text.Length}"
Value = "{Binding Source = {x:Reference entry}, Path=MaxLength}" >
<Setter Property = "TextColor" Value = "Red"/>
</DataTrigger>
Не нужно знать о записи класса, что у него есть свойство с именем «Текст», и это свойство имеет свое собственное свойство «Длина».
И вам не нужно писать случайные имена свойств вручную и делать ошибки в вашей программе (потому что intelli-sense не всегда так интеллектуален).
Эта запись должна быть привязана к какому-то свойству (пока я этого не вижу?!?).
И, очевидно, у вас уже есть другое свойство для MaxLenght (почему эта переменная, я не знаю. Не очень часто иметь свою переменную MaxLength. Вы уверены, что это то, что вам нужно?).
Таким образом, все, что вам нужно сделать, это сравнить длину одного строкового свойства с другим свойством. Здесь нет ничего общего с визуальными элементами.
Обновлено: взгляните на этот ответ, вы можете узнать больше отсюда, чем из документов... https://stackoverflow.com/a/73686153/6643940
Это шаблон пользовательского элемента управления: какой-то Entry со счетчиком слов. Вот почему мне нужно свойство EntryLength. <controls:MyEntry Margin = "25" EntryLength = "30" BorderColor = "{StaticResource Yellow100Accent}" ControlTemplate = "{StaticResource MyEntryTemplate}" />
Я не совсем понимаю, какое решение вы предлагаете. Не могли бы вы привести пример. P.S. Прочитал статью, которую вы посоветовали.
@luvairo Хорошо. Что вы делаете с этой записью? Вы вводите что-то правильно? Что вы делаете с этим? Где введённый текст привязки?
Смотри, я отредактировал вопрос
@luvairo Я снова спрашиваю. Что вы делаете с этой записью. Где ваш текст ввода привязан к строковому свойству? Ни один код, который вы разместили, даже не намекает, что он для чего-то используется.
Это просто шаблон моего контроля (я только тренируюсь). У меня нет внутреннего кода в ViewModel для этого. Вы хотите увидеть файл MyEntry.cs? Извините за непонимание)
@luvairo в тот момент, когда вы попытаетесь использовать его для чего-то, вы поймете, что я имею в виду. Попробуйте использовать его, так как вы видите необходимость шаблонной привязки к тексту. И тогда вы увидите, что можете использовать то самое свойство (точнее, его длину), чтобы определить, что оно достигло MaxLength.
Хорошо, я попробую. У меня еще другая проблема: при запуске приложения индикатор максимальной длины показывает значение int.MaxValue, хотя я явно задал другое. Более того, при вводе первого символа в Entry индикатор меняет значение на правильное. (Посмотрите на файл .png, который я прикрепил). Такое ощущение, что преобразователь запускается до того, как свойство EntryLength получает значение (поэтому int.MaxValue устанавливается из моего определения BindableProperty)
@luvairo И у тебя будут проблемы. Не привязывайтесь к свойствам визуального элемента.
Вы имеете в виду, что я должен добавить некоторые свойства в файл MyEntry.cs вместо привязки к свойствам визуального элемента? Стоит ли вообще использовать DataTrigger?
Не могли бы вы привести пример «хорошего стиля программирования» в моей ситуации. мне будет полезно
@luvairo Да, я советую вам это сделать. Затем вы можете обмануть это отсутствие обновления, вызывая OnPropertyChanged здесь и там. И да, DataTrigger действительно является одним из способов заставить ваш пользовательский интерфейс реагировать на ваши данные. Это достойный выбор для того, что вы пытаетесь сделать.
@luvairo то, что ты делаешь, неплохо. Я не вижу ваш MyEntry.cs, но вижу, что он уже содержит привязываемые свойства, и вы использовали TemplateBinding для доступа к нему. Затем вы можете привязать его к своей ViewModel и сделать шананиганы, например, установить для него значение 0 , прежде чем установить его на 30, поэтому вы запускаете OnPropertyChanged. (и другие хитрости).
Спасибо за ответы) У меня остался последний вопрос: как реализовать сложную анимацию? Например, как сделать анимацию, похожую на стандартную кнопку (где от точки нажатия распространяются волны)
Это класс пользовательских кнопок?
@luvairo, вам действительно следует открыть новый вопрос для этого. Когда мы обсуждаем это в комментариях, другие люди участия не принимают. У меня есть общие знания об анимации. Есть гораздо более компетентные люди, от которых будет гораздо больше пользы, чем от меня.
используйте одно и то же выражение привязки
"{TemplateBinding EntryLength}"
для обоих