Click here to Skip to main content
15,917,628 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I started the MVVM project and set the View binding all events on the TextBlock from ViewModel. I have set 3 commands (MouseEnter, MouseLeave, and MouseDown). But only MouseEnter and MouseDown are firing, MouseLeave event not firing.

I upload my code for help.

This is my View
XML
<Window x:Class="SilentUpdate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:SilentUpdate"
        xmlns:res="clr-namespace:System;assembly=mscorlib"        
        mc:Ignorable="d"
        Background="Gainsboro"
        WindowStartupLocation="CenterScreen" WindowStyle="None"
        Title="" Height="600" Width="1024">
    <Grid>
        <Grid.Resources>
            <ResourceDictionary>
                <Style TargetType="TextBlock" x:Key="IconText">
                    <Setter Property="FontSize" Value="32"/>
                    <Setter Property="Foreground" Value="#ADADAD"/>
                    <Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Segoe UI Symbol"/>
                    <Setter Property="Margin" Value="10,10,10,10"/>
                </Style>
                <res:String x:Key="homeIcon"></res:String>
                <res:String x:Key="settingsIcon"></res:String>
                <res:String x:Key="previewIcon"></res:String>
                <res:String x:Key="runIcon"></res:String>
                <res:String x:Key="saveIcon"></res:String>
                <res:String x:Key="exitIcon"></res:String>
                <res:String x:Key="warningIcon"></res:String>
                <res:String x:Key="folderIcon"></res:String>
            </ResourceDictionary>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel x:Name="Navibar" Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Background="#0096C1">
            <TextBlock Name="home" 
                       Foreground="{Binding HomeColor}"
                       Text="{StaticResource homeIcon}"                        
                       Style="{StaticResource IconText}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseEnter">
                        <i:InvokeCommandAction Command="{Binding EventMouseOver}" 
                                               CommandParameter="{Binding ElementName=home}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeave">
                        <i:InvokeCommandAction Command="{Binding MouseLeaveButton}" 
                                               CommandParameter="{Binding ElementName=home}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding HomeCommand}"
                                               CommandParameter="{Binding ElementName=home}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
            <TextBlock Name="settings"                        
                       Text="{StaticResource settingsIcon}"                        
                       Style="{StaticResource IconText}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseEnter">
                        <i:InvokeCommandAction Command="{Binding EventMouseOver}" 
                                               CommandParameter="{Binding ElementName=settings}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeave">
                        <i:InvokeCommandAction Command="{Binding MouseLeaveButton}" 
                                               CommandParameter="{Binding ElementName=settings}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding SettingCommand}"
                                               CommandParameter="{Binding ElementName=settings}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
            <TextBlock Name="preview" 
                       IsEnabled="{Binding PreviewStatus, Mode=OneWay}"
                       Text="{StaticResource previewIcon}"                        
                       Style="{StaticResource IconText}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseEnter">
                        <i:InvokeCommandAction Command="{Binding EventMouseOver}" 
                                               CommandParameter="{Binding ElementName=preview}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeave">
                        <i:InvokeCommandAction Command="{Binding MouseLeaveButton}" 
                                               CommandParameter="{Binding ElementName=preview}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding PreviewCommand}"
                                               CommandParameter="{Binding ElementName=preview}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
            <TextBlock Name="run" 
                       IsEnabled="{Binding RunStatus, Mode=OneWay}"
                       Text="{StaticResource runIcon}"                        
                       Style="{StaticResource IconText}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseEnter">
                        <i:InvokeCommandAction Command="{Binding EventMouseOver}" 
                                               CommandParameter="{Binding ElementName=run}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeave">
                        <i:InvokeCommandAction Command="{Binding MouseLeaveButton}" 
                                               CommandParameter="{Binding ElementName=run}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding RunCommand}"
                                               CommandParameter="{Binding ElementName=run}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
            <TextBlock Name="save" 
                       IsEnabled="{Binding SaveStatus, Mode=OneWay}"
                       Text="{StaticResource saveIcon}"                        
                       Style="{StaticResource IconText}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseEnter">
                        <i:InvokeCommandAction Command="{Binding EventMouseOver}" 
                                               CommandParameter="{Binding ElementName=save}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeave">
                        <i:InvokeCommandAction Command="{Binding MouseLeaveButton}" 
                                               CommandParameter="{Binding ElementName=save}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding SaveCommand}"
                                               CommandParameter="{Binding ElementName=save}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
            <TextBlock Name="exit" 
                       Text="{StaticResource exitIcon}"                        
                       Style="{StaticResource IconText}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseEnter">
                        <i:InvokeCommandAction Command="{Binding EventMouseOver}" 
                                               CommandParameter="{Binding ElementName=exit}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeave">
                        <i:InvokeCommandAction Command="{Binding MouseLeaveButton}" 
                                               CommandParameter="{Binding ElementName=exit}" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding ExitButtonCommand}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
        </StackPanel>
    </Grid>
</Window>


And here is my ViewModel
C#
using SilentUpdate.Helpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace SilentUpdate.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        #region Property change interface implement
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaiseProperChanged (string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(prop));
            }
        }
        #endregion

        #region Button Status
        // To keep track the active click button
        private TextBlock activeButton;
        private Brush homeColor;
        private bool previewStatus, runStatus, saveStatus;

        public Brush HomeColor
        {
            get { return this.homeColor; }
            set { this.homeColor = value; RaiseProperChanged("HomeColor"); }
        }

        public bool PreviewStatus
        {
            get { return this.previewStatus; }
            set
            {
                this.previewStatus = value;
                RaiseProperChanged("PreviewStatus");
            }
        }

        public bool RunStatus
        {
            get { return this.runStatus; }
            set
            {
                this.runStatus = value;
                RaiseProperChanged("RunStatus");
            }
        }

        public bool SaveStatus
        {
            get { return this.saveStatus; }
            set
            {
                this.saveStatus = value;
                RaiseProperChanged("SaveStatus");
            }
        }
        #endregion

        #region Event Binding        
        // Command for binding to the event
        private ICommand exitButtonCommand, eventMouseOver, eventMouseLeave;
        private ICommand homeCommand, settingCommand, previewCommand, runCommand, saveCommand;

        private bool canExecute = true;                  

        public bool CanExecute
        {
            get { return this.canExecute; }
            set
            {
                if (this.canExecute == value)
                {
                    return;
                }
                this.canExecute = value;
            }
        }

        /// <summary>
        /// Public for binding to Exit button
        /// </summary>
        public ICommand ExitButtonCommand
        {
            get { return this.exitButtonCommand; }
            set
            {
                this.exitButtonCommand = value;
            }
        }

        /// <summary>
        /// Exit the application when Exit button click binding to ExitButtonCommand
        /// </summary>
        /// <param name="obj"></param>
        public void ExitApp(object obj)
        {
            Application.Current.Shutdown();
        }

        /// <summary>
        /// Public for binding to Home button
        /// </summary>
        public ICommand HomeCommand
        {
            get { return this.homeCommand; }
            set
            {
                this.homeCommand = value;
            }
        }

        /// <summary>
        /// Actual home event, will display the home page
        /// This will update the page binding variable
        /// </summary>
        /// <param name="obj"></param>
        public void HomeEvent (object obj)
        {
            // Change the active button
            ChangeActive((TextBlock)obj);
            // Change the button status
            PreviewStatus = false;
            RunStatus = false;
            SaveStatus = false;
            HomeColor = new SolidColorBrush(Colors.White);
            MessageBox.Show("HomeEvent");
        }

        /// <summary>
        /// Public for binding to Setting button
        /// </summary>
        public ICommand SettingCommand
        {
            get { return this.settingCommand; }
            set
            {
                this.settingCommand = value;
            }
        }

        /// <summary>
        /// Actual Setting event, will display the setting page
        /// This will update the page binding variable
        /// </summary>
        /// <param name="obj"></param>
        public void SettingEvent(object obj)
        {
            // Change the active button
            ChangeActive((TextBlock)obj);
            // Change the button status
            PreviewStatus = true;
            RunStatus = false;
            SaveStatus = false;
            MessageBox.Show("SettingEvent");
        }

        /// <summary>
        /// Public for binding to Preview button
        /// </summary>
        public ICommand PreviewCommand
        {
            get { return this.previewCommand; }
            set
            {
                this.previewCommand = value;
            }
        }

        /// <summary>
        /// Actual Preview event, will display the preview page
        /// based on the Messenger sending to the page for the environment 
        /// setting by the setting page        
        /// This will update the page binding variable
        /// </summary>
        /// <param name="obj"></param>
        public void PreviewEvent(object obj)
        {
            // Change the active button
            ChangeActive((TextBlock)obj);
            // Change the button status
            PreviewStatus = true;
            RunStatus = true;
            SaveStatus = false;
            MessageBox.Show("PreviewEvent");
        }

        /// <summary>
        /// Public for binding to Run button
        /// </summary>
        public ICommand RunCommand
        {
            get { return this.runCommand; }
            set
            {
                this.runCommand = value;
            }
        }

        /// <summary>
        /// Actual Preview event, will display the after run page
        /// based on the Messenger sending to the page for the environment 
        /// setting by the setting page and the selection of the list file
        /// from the Preview page
        /// This will update the page binding variable
        /// </summary>
        /// <param name="obj"></param>
        public void RunEvent(object obj)
        {
            // Change the active button
            ChangeActive((TextBlock)obj);
            // Change the button status
            PreviewStatus = true;
            RunStatus = true;
            SaveStatus = true;
            MessageBox.Show("RunEvent");
        }

        /// <summary>
        /// Public for binding to Save button
        /// </summary>
        public ICommand SaveCommand
        {
            get { return this.saveCommand; }
            set
            {
                this.saveCommand = value;
            }
        }

        /// <summary>
        /// Actual Save event, will generate the PDF file log
        /// And launch the PDF file based on default application setting
        /// </summary>
        /// <param name="obj"></param>
        public void SaveEvent(object obj)
        {
            ChangeActive((TextBlock)obj);
            MessageBox.Show("SaveEvent");
        }

        /// <summary>
        /// This event uses by all button to change color to active state
        /// </summary>
        public ICommand EventMouseOver
        {
            get { return this.eventMouseOver; }
            set
            {
                this.eventMouseOver = value;
            }
        }

        /// <summary>
        /// Actual mouse enter event for binding command EventMouseOver
        /// </summary>
        /// <param name="obj">The target object of button</param>
        public void MouseOverButton(object obj)
        {
            // Casting the object
            TextBlock target = (TextBlock)obj;
            if (activeButton == null)
            {
                // High light target 
                activeButton = target;
            }
            // High light target 
            HighLightText(target, true);
        }

        /// <summary>
        /// This event uses by all button to change color to inactive state
        /// </summary>
        public ICommand EventMouseLeave
        {
            get { return this.eventMouseLeave; }
            set { this.eventMouseLeave = value; }
        }

        /// <summary>
        /// Actual mouse leave event for binding command EventMouseLeave
        /// </summary>
        /// <param name="obj">The target object of button</param>
        private void MouseLeaveButton(object obj)
        {
            // Casting the object
            TextBlock target = (TextBlock)obj;
            if (target.Equals(activeButton) == false)
            {
                HighLightText(target, false);
            }
            HighLightText(activeButton, true);
        }           

        /// <summary>
        /// Update the canExecute property
        /// </summary>
        /// <param name="obj"></param>
        public void ChangeCanExecute(object obj)
        {
            canExecute = !canExecute;
        }

        public MainViewModel()
        {
            exitButtonCommand = new RelayCommand(ExitApp, Param => this.canExecute);
            eventMouseOver = new RelayCommand(MouseOverButton);
            eventMouseLeave = new RelayCommand(MouseLeaveButton);
            homeCommand = new RelayCommand(HomeEvent);
            settingCommand = new RelayCommand(SettingEvent);
            previewCommand = new RelayCommand(PreviewEvent);
            runCommand = new RelayCommand(RunEvent);
            saveCommand = new RelayCommand(SaveEvent);
            // Set the Preview status disable when start
            PreviewStatus = false;
            // Set the Run status disable when start
            RunStatus = false;
            // Set the Save status disable when start
            SaveStatus = false;
            // HomeColor
            HomeColor = new SolidColorBrush(Colors.White);
        }

        private void HighLightText(TextBlock target, bool isHighlight)
        {
            if (isHighlight)
            {
                target.Foreground = new SolidColorBrush(Colors.White);
            }
            else
            {
                target.Foreground = new SolidColorBrush(System.Windows.Media.Color.FromArgb(68, 173, 173, 173));
            }
        }

        private void ChangeActive (TextBlock target)
        {
            if (activeButton != null)
            {
                HighLightText(activeButton, false);
            }
            activeButton = target;
            HighLightText(activeButton, true);
            activeButton.ReleaseMouseCapture();
            target.ReleaseMouseCapture();
            HomeColor = new SolidColorBrush(System.Windows.Media.Color.FromArgb(68, 173, 173, 173));
        }
    }
}


What I have tried:

Try to change event MouseLeave from LostFocus but no help
Posted
Updated 14-Mar-17 19:45pm

1 solution

I have a problem with your understanding of MVVM. You have UI code in the ViewModel (VM) where it does not belong. All the UI code belongs in the XAML page &/or XAML page code-behind.

Think of VMs as a loosely coupled layer between your data and the UI - it knows nothing about the UI itself, only the data. A more official description would be: "The view model is an abstraction of the view exposing public properties and commands. In the VM could also be been described as a state of the data in the model".

if you don't want to put the UI logic in a code-behind, you have other options available to you. For example: If you are setting a color based on a state, then a ValueConverter or a MultiValueConverter in the binding would be the a good choice.

Behaviors are good for more complex requirements than a ValueConverter offers. For example, I have a GridHelpers behavior that helps me generate Grid.Row & Grid.Colums dynamically with sizing in the ItemPanel of a ItemsControl. The VM is totally unaware of this, all the VM does is expose an OnservableCollection of data.

There are other methods that I am sure others will chime in with however these two will meet 100% of your requirements for the code from above.

For the buttons, I would bind to the Click event, not the MouseDown event. MouseEnter, MouseLeave, MouseDown trigger events for UI state changes should remain in the XAML, not in the VM. If you don't want to do it in XAML, then bind to the events in the code-behind where any UI code belongs.
 
Share this answer
 
v3
Comments
Thang_Duong 15-Mar-17 8:45am    
Thanks so much. My mistake I should leave the UI logic in the View not ViewModel
Graeme_Grant 15-Mar-17 10:23am    
All good ... part of the learning process. We all go through it. Just glad that I could be of help. :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900