У меня есть пользовательский элемент управления, для которого я должен изменить цвет в зависимости от наведения мыши, щелчка или отсутствия. После МВВМ. Это код, который у меня есть:
Пользовательский контроль в XAML
<userControls:NC DataContext = "{Binding NCVM}" >
</userControls:NC>
Модель представления пользовательского элемента управления
public class NCVM : ObservableObject
{
public NCVM()
{
}
private NCState _currentState = NCState.InActive;
public NCState CurrentState
{
get => _currentState;
set
{
_currentState = value;
switch (_currentState)
{
case NCState.InActive:
ForegroundColor = System.Windows.Media.Brushes.LightGray;
IsActive = false;
break;
case NCState.Active:
ForegroundColor = System.Windows.Media.Brushes.White;
IsActive = true;
break;
case NCState.Hovered:
ForegroundColor = System.Windows.Media.Brushes.White;
IsActive = false;
break;
default:
ForegroundColor = System.Windows.Media.Brushes.LightGray;
IsActive = false;
break;
}
}
}
public bool _isActive;
public bool IsActive
{
get => _isActive;
set => SetProperty(ref _isActive, value);
}
private System.Windows.Media.Brush _foregroundColor = System.Windows.Media.Brushes.LightGray;
public System.Windows.Media.Brush ForegroundColor
{
get => _foregroundColor;
set => SetProperty(ref _foregroundColor, value);
}
}
Модель вида главного окна
public class MWVM : BVM
{
#region Private Variables
private NCVM _NCVM = new();
#endregion
public MWVM()
{
NCVM.CurrentState = NCState.Active;
}
#region Public Properties
public NCVM NCVM
{
get => _NCVM;
set => SetProperty(ref _NCVM, value);
}
#endregion
}
Прямо сейчас он становится активным для проверки. Теперь я должен сделать это вручную, чтобы он менялся при наведении, но не понимал, как это сделать с привязкой.
Применение цвета для состояния в пользовательском интерфейсе обычно не связано с моделью представления. Для чего предназначены свойства CurrentState
и IsActive
? Что UserControl
делать с ними? Где находится CurrentState
? Должен ли UserControl
устанавливать CurrentState
и IsActive
? Есть ли необходимость, чтобы кисти были в модели представления, а не в самой UserControl
?
@Orace Я попробовал <Style.Triggers> в соответствии с вашим ответом. Он не работает внутри пользовательского элемента управления, говоря, что «значение типа Setter не может быть добавлено в коллекцию или словарь типа TriggerCollection». Раньше использовал триггеры отдельно, они работают, не знаю, почему не здесь.
@thatguy Я не писал этот базовый код, но должен внести изменения. CurrentState предназначен для отслеживания состояния (зависание, неактивность и т. д.). Внешний вид пользовательского элемента управления (в основном кнопки) будет изменен в зависимости от наведения или нет. Есть несколько кнопок, поэтому для отслеживания есть эти свойства, для отслеживания и изменения стиля соответственно. Что касается кистей, то нет, я также могу держать их под контролем пользователя.
@tcmsh, это потому, что ты поставил сеттер рядом с триггером, а не внутри ?♂️
@orace о, я так не делал, лол. Здесь <userControls:NC DataContext = "{Binding NCVM}" > <Style> <Style.Triggers> <Setter ........ </Style.Triggers> </Style> </userControls:NC>
@tcmsh Используются ли эти свойства где-либо еще, кроме пользовательского интерфейса, например. используются ли они в логике приложения?
@thatguy Нет, только для этого пользовательского интерфейса, вот и все.
Вы можете взглянуть на Триггер события или триггеры в целом, чтобы стилизовать свой элемент управления.
*Редактировать: Небольшой пример, MVVM не рассматривается, просто чтобы вы могли взглянуть на триггеры.
Пользовательский контроль:
<UserControl x:Class = "WpfApp1.UserControl1"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:WpfApp1"
mc:Ignorable = "d"
d:DataContext = "{d:DesignInstance Type = {x:Type local:UserControl1}}"
Height = "200" Width = "400">
<UserControl.Style>
<Style TargetType = "UserControl">
<Style.Triggers>
<DataTrigger Binding = "{Binding RelativeSource = {RelativeSource Self}, Path=IsMyPropSet}" Value = "True">
<Setter Property = "Background" Value = "Turquoise"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
<GroupBox Header = "I am your usercontrol">
<Button Width = "100" Height = "35" Content = "Toggle Property" Click = "Button_Click"/>
</GroupBox>
</UserControl>
и код программной части:
public partial class UserControl1 : UserControl, INotifyPropertyChanged
{
public UserControl1()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public bool IsMyPropSet { get; set; }
private void Button_Click(object sender, RoutedEventArgs e)
{
IsMyPropSet = !IsMyPropSet;
RaisePropertyChanged(nameof(IsMyPropSet));
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Привет. Я попробую это. Но я должен сделать это из файла модели представления. Возможно ли это сделать оттуда? Тем временем я пробую триггерный подход.
Я только что отредактировал свой ответ, чтобы дать вам небольшой пример.
Спасибо за пример. Должен ли я определить этот новый стиль в файле пользовательского управления или в XAML, где я его использую.
Вы даже можете поместить стиль в ResourceDictionary, чтобы иметь возможность использовать его с несколькими пользовательскими элементами управления. Если это единственный пользовательский элемент управления, в котором вы хотите использовать этот стиль, вы можете оставить его в файле пользовательского элемента управления.
Шаблон MVVM предназначен для отделения пользовательского интерфейса (представления) от данных и самой логики приложения. Ваш пример нарушает MVVM тем, что сохраняет кисти и визуальные состояния в модели представления. Модель представления должна предоставлять только данные и команды для привязки, но не элементы пользовательского интерфейса, и она не должна содержать логику, относящуюся к пользовательскому интерфейсу, точно так же, как управление визуальными состояниями или внешним видом. Его слишком часто неправильно понимают как создание модели представления и просто размещение всего там.
В вашем случае, я думаю, вы можете решить свою проблему, переместив все в стиль. Следующий XAML должен показать ваш userControls:NC
. Существуют триггеры для разных состояний, таких как Неполноценный, Наведите курсор/Наведите курсор мыши. Обратите внимание, что вам необходимо установить Background
, в противном случае элемент управления не будет участвовать в тестировании на попадание и, например. свойство IsMouseOver
не будет True
, даже если вы наведете на него курсор. Для отсутствия фона используйте Transparent
(что не равнозначно отсутствию установки значения).
<UserControl ...>
<UserControl.Style>
<Style TargetType = "{x:Type userControls:NC}">
<!-- Background must be set at least to "Transparent" -->
<Setter Property = "Background" Value = "Black"/>
<!-- Default -->
<Setter Property = "Foreground" Value = "LightGray"/>
<Style.Triggers>
<!-- Hovered -->
<Trigger Property = "IsMouseOver" Value = "True">
<Setter Property = "Foreground" Value = "White"/>
</Trigger>
<!-- Disabled -->
<Trigger Property = "IsEnabled" Value = "False">
<Setter Property = "Foreground" Value = "LightGray"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Style>
<!-- Dummy element for demonstration purposes of foreground -->
<TextBlock Text = "This text shows the foreground"/>
</UserControl>
Спасибо за объяснение и ответ. Я сделал все соответственно. Можете ли вы сказать, что это за «BorderUserControl» в целевом типе, он не идентифицируется. Я пробовал менять имена, но не получилось.
@tcmsh Извините, остатки от тестирования. Это должно быть тип вашего UserControl
.
Использование шаблона MVVM для обработки стилей не рекомендуется. XAML имеет достаточно возможностей, чтобы сделать это самостоятельно. Отвечает ли это на ваш вопрос? wpf c# Изменить фон при наведении мыши