元素变为非活动状态时会触发事件

时间:2019-05-03 12:17:27

标签: c# wpf mvvm

我有一个WPF-MVVM应用程序,可以与PLC进行通信。按下按钮时,请在plc停留true中使用bool变量,如果其释放或失去焦点或变为非活动状态,则该变量应再次变为false

我具有通过事件实现的按钮。 (由于存在多点触摸屏,因此同时发生了PreviewTouchUpPreviewTouchDown事件。)

<UserControl x:Class="..."
    ...
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    ... >
    ...
    <Button>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="PreviewMouseLeftButtonDown">
                <i:InvokeCommandAction Command="{Binding CmdSetFlag}" CommandParameter="PlcVariable" />
            </i:EventTrigger>
            <i:EventTrigger EventName="PreviewMouseLeftButtonUp">
                <i:InvokeCommandAction Command="{Binding CmdResetFlag}" CommandParameter="PlcVariable" />
            </i:EventTrigger>
            <!-- followed by touch events -->
        </i:Interaction.Triggers>
    </Button>
    ...
</UserControl>

在ViewModel中是命令CmdSetFlagCmdResetFlag

public MyViewModel : INotifyPropertyChanged
{

    public MyViewModel(string pageName)
    {
        CmdResetFlag = new ActionCommand((p) => MyPlc.WriteVar(p.ToString(), false));
        CmdSetFlag = new ActionCommand((p) => MyPlc.WriteVar(p.ToString(), true));
    }

    /// <summary>
    ///   Sets a bool on the plc to false.
    /// </summary>
    public ICommand CmdResetFlag { get; private set; }

    /// <summary>
    ///   Sets a bool on the plc to true.
    /// </summary>
    public ICommand CmdSetFlag { get; private set; }
}

因此,如果鼠标或触摸失败,则会触发事件,并以plc变量名称作为参数调用命令。

然后有一个plc客户端类可以自己编写plc:

/// <summary>
///   MyPlc is a static wrapper class.
///   It sends write and read commands to the actual plc implementation.
/// </summary>
public class MyPlc
{
    static MyPlc()
    {
        MyActualPlc = new ...Plc();
    }

    /// <summary>
    ///   The actual plc interface in use. There may any type of plc.
    /// </summary>
    private IPlc MyActualPlc { get; set; }

    /// <summary>
    ///   Write a variable to the plc.
    /// </summary>
    /// <param name="varName">The name of the variable.</param>
    /// <param name="value">The value to write.</param>
    public void WriteVar(string varName, object value)
    {
        int myHandle = PlcClient.CreateVariableHandle(varName);
        PlcClient.WriteAny(myHandle, value);
        PlcClient.DeleteVariableHandle(myHandle);
    }
}

释放鼠标或触摸时,变量再次变为false。因此,在释放按钮之前,plc上的值将保持为真。

这很好,直到出现类似事件打开的窗口之类的中断为止。然后PreviewMouseUpPreviewTouchUp事件均不会触发。

我也尝试了LostFocus,但没有成功。

是否有可以代替PreviewMouseUpPreviewTouchUp使用的事件?

2 个答案:

答案 0 :(得分:0)

也许this是解决方案。

通过使用通过行为添加的事件IsEnabledChanged(和IsVisibleChanged)为我 解决了问题。

也许这仅是因为打开一个窗口时按钮被禁用而导致我打断了我的问题。

<UserControl x:Class="..."
    ...
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ext="clr-namespace:NamespaceOfMyBehavior"
    ... >
    ...
        <Button...>
            <!-- The triggers looks like above -->
            <i:Interaction.Triggers>...</i:Interaction.Triggers>  
            <i:Interaction.Behaviors>
                <ext:PlcButtonBehavior PlcVar="PlcVar"/>
            </i:Interaction.Behaviors>
        </Button>
        ...
</UserControl>

Behavior类看起来像

public class PlcButtonBehavior : Behavior<Button>
{
    public static readonly DependencyProperty InvalidValueProperty =
        DependencyProperty.Register(
            "InvalidValue", typeof(string), typeof(PlcButtonBehavior),
            new PropertyMetadata(string.Empty, (d, e) =>
                (PlcButtonBehavior)d).Update()));

    public string PlcVar
    {
        get { return (string)GetValue(InvalidValueProperty); }
        set { SetValue(InvalidValueProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.IsEnabledChanged += AssociatedObject_IsEnabledChanged;
        AssociatedObject.IsVisibleChanged += IsVisibleChanged_IsVisibleChanged;
        Update();
    }

    protected override void OnDetaching()
    {
        AssociatedObject.IsEnabledChanged -= AssociatedObject_IsEnabledChanged;
        AssociatedObject.IsVisibleChanged -= IsVisibleChanged_IsVisibleChanged;
        base.OnDetaching();
    }

    private void AssociatedObject_IsEnabledChanged(
        object sender, DependencyPropertyChangedEventArgs e)
    {
        Update();
    }

    private void IsVisibleChanged_IsVisibleChanged(
        object sender, DependencyPropertyChangedEventArgs e)
    {
        Update();
    }

    private void Update()
    {
        if (AssociatedObject is Button button
            && button.IsVisible
            && button.IsEnabled
            && AssociatedObject.IsPressed)
        {
            Plc.SetFlag(PlcVar);           
        }
        else
        {
            Plc.ResetFlag(PlcVar);             
        }
    }
}

要将行为中的事件设置为触发器,将不起作用。

答案 1 :(得分:-1)

“直到出现类似事件打开的窗口之类的中断为止,它都可以正常工作”,我不确定我是否理解正确,当控件(或应用程序)失去焦点时您的事件不起作用? 也许您看起来像Application.Deactivated Event-当应用程序停止成为前台应用程序时发生。