@maximsemin23

Как создать такой элемент в wpf?

Мне нужна кнопка, которая выглядит как обычный текст, и при этом меняет свой цвет на нужный мне при наведении мыши. И выглядет должно как textblock, а не как button
  • Вопрос задан
  • 192 просмотра
Решения вопроса 1
habcerga1
@habcerga1
Тут маленький мануал который описан очень сжато и читать его нужно просматривая сам проект. Ссылка на него.

Для того чтобы сделать свой customcontrol нужно две вещи:
1. View представление самого элемента.
2. Класс который будем контекстом данных для этого View представления.

Наше приложение будет базироваться на шаблоне MVVM, если незнаком с этим читаем тут. Так же необходимо понимать что такое binding в WPF,если незнаем читаем тут и тут. Если кратко то связывание, это такая штука
которая позволяет обновлять состояние UI элемента при изменении его свойств в контексте данных, если этого не сделать то тогда обновлять состояние в UI нужно будет через Dispacher а это будет фризить
наш UI и так делать не нада. Поэтому добавим в наш проект Папку Services и туда добавим классы ObservableObject и RelayCommand (Код все[ классов находиться в репозитории). В ObservableObject будет описан механизм связывания свойств и мы будет просто наследоваться от этого класса, вызывая метод OnPropertyChanged в set параметре свойств.

Связывание наших свойств разделим на два этапа, сначала сделаем события обновления данных в самой модели кнопки а затем укажем к какому контексту данных привязаться и с какими свойствами связать в XAML (сама наша кнопка).

Сначала опишем интерфейс кнопки типом IButtonStyle и создадим абстрактный класс AButton который наследует ObservableObject,IButtonStyle. В классе AButton добавим поля отражающие свойства в IButtonStyle.

private string _content;
        public string content
        {
            get => _content;
            set { OnPropertyChanged(ref _content, value); }
        }


Тут реализовано свойство наследованное из интерфейса IButtonStyle (content) которое возвр. поле _content и устанавливает значение с помощью метода OnPropertyChanged(ref _content, value), и тоже самое проделаем со всеми остальными свойствами которые мы наследуем. Потом мы свяжем эти свойства со свойствами нашего UserControl в XAML.

<Label Content="{Binding content}" Foreground="{Binding fontColor}" FontSize="{Binding fontSize}"/>


Теперь нам нужно сделать так чтобы при наведении курсора на наш элемент он изменял цвет. Для этого нам нужно создать свойства зависимости типа RelayCommand для нашей кнопки

private RelayCommand _mouseEnterCommand;
        /// <summary>
        /// Команда входа мышки в поле контролера
        /// </summary>
        public RelayCommand MouseEnterCommand
        {
            get { return _mouseEnterCommand; }
            set
            {
                OnPropertyChanged(ref _mouseEnterCommand, value);
            }
        }

        private RelayCommand _mouseLeaveCommand;
        /// <summary>
        /// Команда покидания мышки поля контролера
        /// </summary>
        public RelayCommand MouseLeaveCommand
        {
            get { return _mouseLeaveCommand; }
        }

        private RelayCommand _mouseDownCommand;
        /// <summary>
        /// Команда щелчка мышки
        /// </summary>
        public RelayCommand MouseDownCommand
        {
            get { return _mouseDownCommand; }
        }


И сделаем пару событий и методов для непосредственной установки значений (цвет или размер шрифта)

event Action _mouseEnter;
        event Action _mouseLeave;

        void MouseEnterEventMethod()
        {
            fontColor = fontColorMouseEnter;
        }
         void MouseLeaveEventMethod()
        {
            fontColor = fontColorNormal;
        }

        private void MouseEnter()
        {
            this._mouseEnter.Invoke();
        }

        private void MouseLeave()
        {
            this._mouseLeave.Invoke();
        }

        public void MouseEnter(object param)
        {
            MouseEnter();
        }

        public void MouseLeave(object param)
        {
            MouseLeave();
        }


И подпишемся на это в конструкторе класса

public AButton(string _content)
        {
            content = _content;
            _mouseEnter += this.MouseEnterEventMethod;
            _mouseLeave += this.MouseLeaveEventMethod;

            this._mouseEnterCommand = new RelayCommand(MouseEnter);
            this._mouseLeaveCommand = new RelayCommand(MouseLeave);
        }


И так у нас теперь есть свойства content, fontColor, fontColorNormal, fontColorMouseEnter и комманды MouseEnterCommand, MouseLeaveCommand, MouseDownCommand готовые для сзязывания.

Ну и сделаем пару классов наших кнопок
class ButtonStyleA : AButton
    {
       public ButtonStyleA(string _content) : base()
        {
            content = _content;
            base.fontColor = "#FF5733";
            base.fontColorNormal = "#FF5733";
            base.fontColorMouseEnter = "#61FF33";
            fontSize = 16;
        }
    }

class ButtonStyleB : AButton
    {
        public ButtonStyleB(string _content) : base()
        {
            content = _content;
            fontColor = "#33B5FF";
            fontColorNormal = "#33B5FF";
            fontColorMouseEnter = "#E933FF";
            fontSize = 12;
        }
    }


Теперь нам нужно создать контекст данных для нашего элемента, поэтому в папке ViewModels Создадим класс

public class MenuButtonViewModel
    {
        public AButton MenuButton { get; set; }

        public MenuButtonViewModel(AButton menuButton)
        {
            MenuButton = menuButton;
        }
    }


Очень часто все связывания и Комманды реализовывают иммено в классе контекста данных (MenuButtonViewModel).

Создадим наш UserControl в папке Views назовем его MyButton и добавим ссылку на класс MouseBehaviour.

xmlns:u="clr-namespace:WpfMvvmDemo.Services"

Теперь свяжем события MouseMoveCommand, MouseLeaveCommand, MouseDownCommand с нашими свойствами типа RelayCommand.

<Grid u:MouseBehaviour.MouseMoveCommand="{Binding MenuButton.MouseEnterCommand}" u:MouseBehaviour.MouseLeaveCommand="{Binding MenuButton.MouseLeaveCommand}" u:MouseBehaviour.MouseDownCommand="{Binding MenuButton.MouseDownCommand}">


И также свяжем свойсва Label со свойствами AButton

<Label Content="{Binding MenuButton.content}" Foreground="{Binding MenuButton.fontColor}" FontSize="{Binding MenuButton.fontSize}"/>


Теперь нам нужен контекст данных для главного окна нашего приложения. Назовем его RootViewModel и создадим в нем две кнопки разных типов ButtonStyleA и ButtonStyleВ.

public class RootViewModel : ObservableObject
    {
        public MenuButtonViewModel MainPageButton { get; set; }
        public MenuButtonViewModel SecondPageButton { get; set; }

        public RootViewModel()
        {
            MainPageButton = new MenuButtonViewModel(new ButtonStyleA("Главная"));
            SecondPageButton = new MenuButtonViewModel(new ButtonStyleB("Вторая"));
        }

        private void ChangeToMainPage()
        {

        }


        private void ChangeToSecondPage()
        {

        }
    }


В Классе MainWindow создадим экземпляр типа RootViewModel и сделаем его контекстом данных для MainWindow

private RootViewModel RootVM;
        public MainWindow()
        {
            InitializeComponent();
            RootVM = new RootViewModel();
            this.DataContext = RootVM;
        }


В XAML представлении нашего главного окна MainWindow добавим ссылку на наш CustomController xmlns:bn="clr-namespace:WpfMvvmDemo.Views"
и теперь пересоберем проект а то ide может не увидеть наши кнопки, и потом добавим сообственно сами кнопки и установим для них контекст данных (это те свойства типа MenuButtonViewModel которые мы создали в RootViewModel)
<Grid >
        <StackPanel Orientation="Vertical">
            <bn:MyButton DataContext="{Binding MainPageButton}" />
            <bn:MyButton DataContext="{Binding SecondPageButton}"/>
        </StackPanel>
    </Grid>


Ну вот собственно и все, можно запускать и радоваться. За г0внокод просьба не ругать.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы