Привязка цвета переднего плана элемента управления к наведению мыши

У меня есть пользовательский элемент управления, для которого я должен изменить цвет в зависимости от наведения мыши, щелчка или отсутствия. После МВВМ. Это код, который у меня есть:

Пользовательский контроль в 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
}

Прямо сейчас он становится активным для проверки. Теперь я должен сделать это вручную, чтобы он менялся при наведении, но не понимал, как это сделать с привязкой.

Использование шаблона MVVM для обработки стилей не рекомендуется. XAML имеет достаточно возможностей, чтобы сделать это самостоятельно. Отвечает ли это на ваш вопрос? wpf c# Изменить фон при наведении мыши

Orace 16.03.2022 10:20

Применение цвета для состояния в пользовательском интерфейсе обычно не связано с моделью представления. Для чего предназначены свойства CurrentState и IsActive? Что UserControl делать с ними? Где находится CurrentState? Должен ли UserControl устанавливать CurrentState и IsActive? Есть ли необходимость, чтобы кисти были в модели представления, а не в самой UserControl?

thatguy 16.03.2022 10:22

@Orace Я попробовал <Style.Triggers> в соответствии с вашим ответом. Он не работает внутри пользовательского элемента управления, говоря, что «значение типа Setter не может быть добавлено в коллекцию или словарь типа TriggerCollection». Раньше использовал триггеры отдельно, они работают, не знаю, почему не здесь.

tcmsh 16.03.2022 11:02

@thatguy Я не писал этот базовый код, но должен внести изменения. CurrentState предназначен для отслеживания состояния (зависание, неактивность и т. д.). Внешний вид пользовательского элемента управления (в основном кнопки) будет изменен в зависимости от наведения или нет. Есть несколько кнопок, поэтому для отслеживания есть эти свойства, для отслеживания и изменения стиля соответственно. Что касается кистей, то нет, я также могу держать их под контролем пользователя.

tcmsh 16.03.2022 11:07

@tcmsh, это потому, что ты поставил сеттер рядом с триггером, а не внутри ?‍♂️

Orace 16.03.2022 11:15

@orace о, я так не делал, лол. Здесь <userControls:NC DataContext = "{Binding NCVM}" > <Style> <Style.Triggers> <Setter ........ </Style.Triggers> </Style> </userControls:NC>

tcmsh 16.03.2022 11:21

@tcmsh Используются ли эти свойства где-либо еще, кроме пользовательского интерфейса, например. используются ли они в логике приложения?

thatguy 16.03.2022 11:24

@thatguy Нет, только для этого пользовательского интерфейса, вот и все.

tcmsh 16.03.2022 11:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете взглянуть на Триггер события или триггеры в целом, чтобы стилизовать свой элемент управления.

*Редактировать: Небольшой пример, 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));
    }
}

Привет. Я попробую это. Но я должен сделать это из файла модели представления. Возможно ли это сделать оттуда? Тем временем я пробую триггерный подход.

tcmsh 16.03.2022 10:17

Я только что отредактировал свой ответ, чтобы дать вам небольшой пример.

Schmittmuthelm 16.03.2022 10:33

Спасибо за пример. Должен ли я определить этот новый стиль в файле пользовательского управления или в XAML, где я его использую.

tcmsh 16.03.2022 11:12

Вы даже можете поместить стиль в ResourceDictionary, чтобы иметь возможность использовать его с несколькими пользовательскими элементами управления. Если это единственный пользовательский элемент управления, в котором вы хотите использовать этот стиль, вы можете оставить его в файле пользовательского элемента управления.

Schmittmuthelm 16.03.2022 11:50
Ответ принят как подходящий

Шаблон 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 16.03.2022 12:39

@tcmsh Извините, остатки от тестирования. Это должно быть тип вашего UserControl.

thatguy 16.03.2022 12:49

Другие вопросы по теме