Wpf XAML mouseleave事件未在命令绑定中触发 [英] Wpf XAML mouseleave event not firing in command binding

查看:70
本文介绍了Wpf XAML mouseleave事件未在命令绑定中触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我启动了MVVM项目,并在ViewModel上设置了TextBlock上的View绑定所有事件。我设置了3个命令(MouseEnter,MouseLeave和MouseDown)。但是只有MouseEnter和MouseDown被触发,MouseLeave事件没有被触发。



我上传我的代码求助。



这是我的观点

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

<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



And here is my ViewModel

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



What I have tried:

Try to change event MouseLeave from LostFocus but no help

推荐答案

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.
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.


这篇关于Wpf XAML mouseleave事件未在命令绑定中触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆