在代码隐藏中处理事件以及在某些事件上调用视图模型的命令

Handle an event in code behind as well as Invoke a view model's command on some event

这里是概述:

我正在使用自定义控件 (CusCtrl) 来显示任务栏图标,它还有一个 Popup 属性。因此,当您单击该图标时,CusCtrl 会显示弹出窗口。

我正在使用 UserControl 设置弹出窗口的子项(比方说 UC1)。

我正在使用 ViewModel 设置 CusCtrl 的 DataContext,因此即使 UC1 也与相应的 ViewModel 绑定(比方说 VM1

现在 UC1 有一些元素 - 标签,点击标签我需要做两件事:

  1. 在视图模型 VM1 上调用命令 -

    从命令我需要将一些视图模型的属性作为参数传递并打开一些 window UI.

  2. 关闭弹出窗口 -

    为此,我考虑过在 UserControl 的代码后面监听 MouseUp 事件,然后触发一个路由事件(FirePopUpClose - 此事件在 UserControl UC1 中定义),它将由应用程序处理,然后从 handler, Custom Conntrol 的 ClosePopUp 方法将被调用。

我知道如何使用 Interactivity dll 在标签上的 MouseUp 事件上调用命令,但是我怎样才能引发 FirePopUpClose 路由事件?

或者如何在标签上应用 MouseUp 事件处理程序并将命令绑​​定到该标签?

我什至认为这是正确的方法还是有一些更好的清洁方法来执行某些 UI 操作以及通过坚持使用 MVVM 关闭弹出窗口?

下一个解决方案呢;尝试使用 Popup.IsOpen 属性 (here is the information about, and here is the example of usage #867 – Controlling Whether a Popup Is Open Using Data Binding )。直接或通过 CusCtrl 用户控件的 DependencyProperty 将其绑定到 UC1 DataContext(您必须在封装 Popup 的控件中创建 属性)。就是这样,这样你就可以在没有事件的情况下管理弹出窗口的打开或关闭。

更新 尝试下一个: 1.主要Xaml:

<Window x:Class="PopupIsOpenDataBindingHelpAttempt.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:popupIsOpenDataBindingHelpAttempt="clr-namespace:PopupIsOpenDataBindingHelpAttempt"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <popupIsOpenDataBindingHelpAttempt:DemoMainViewModel/>
</Window.DataContext>
<Window.Resources>
    <DataTemplate x:Key="PopupInnerControlDataTemplateKey" DataType="{x:Type popupIsOpenDataBindingHelpAttempt:TaskBarDemoViewModel}">
        <Grid Width="150" Height="85">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Text="{Binding TextString}"
                       Margin="5" Foreground="Red"
                       Width="150" TextWrapping="WrapWithOverflow"
                       VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
            <Button    Grid.Row="1" Content="Press to close" Command="{Binding PopupInnerButtonCommand}"
                    VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
        </Grid>
    </DataTemplate>
    <Image x:Key="ImageControl" Source="Pic/2015_10_16_Bing_en-US.jpg" IsHitTestVisible="False"/>
</Window.Resources>
<Grid Width="75" Height="75" HorizontalAlignment="Center" VerticalAlignment="Center">
    <popupIsOpenDataBindingHelpAttempt:TaskBarIconProjectDemo 
        ButtonContentProperty="{StaticResource ImageControl}"
        ButtonCommandProperty="{Binding ShowPopupCommand}"
        PopupIsOpenProperty="{Binding IsPopupOpen, UpdateSourceTrigger=PropertyChanged}"
        PopupInnerContentControlDataContext="{Binding TaskBarDemoViewModel, UpdateSourceTrigger=PropertyChanged}"
        PopupInnerContentControlContentTemplate="{StaticResource PopupInnerControlDataTemplateKey}"/>
</Grid>

2.弹窗封装XAMl:

<UserControl x:Class="PopupIsOpenDataBindingHelpAttempt.TaskBarIconProjectDemo"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" x:Name="This">
<Grid>
    <Button Style="{StaticResource SpecialButtonStyle}" Command="{Binding ElementName=This, Path=ButtonCommandProperty}" 
            Content="{Binding ElementName=This, Path=ButtonContentProperty}"></Button>
    <Popup IsOpen="{Binding ElementName=This, Path=PopupIsOpenProperty}">
        <ContentControl Content="{Binding ElementName=This, Path=PopupInnerContentControlDataContext}" 
                        ContentTemplate="{Binding ElementName=This, Path=PopupInnerContentControlContentTemplate}"/>
    </Popup>
</Grid>

3.弹出封装控制代码在后面(依赖属性):

public partial class TaskBarIconProjectDemo : UserControl
{
    public static readonly DependencyProperty ButtonCommandPropertyProperty = DependencyProperty.Register("ButtonCommandProperty", typeof (ICommand), typeof (TaskBarIconProjectDemo), new PropertyMetadata(default(ICommand)));
    public static readonly DependencyProperty PopupIsOpenPropertyProperty = DependencyProperty.Register("PopupIsOpenProperty", typeof (bool), typeof (TaskBarIconProjectDemo), new PropertyMetadata(default(bool)));
    public static readonly DependencyProperty PopupInnerContentControlDataContextProperty = DependencyProperty.Register("PopupInnerContentControlDataContext", typeof (object), typeof (TaskBarIconProjectDemo), new PropertyMetadata(default(object)));
    public static readonly DependencyProperty PopupInnerContentControlContentTemplateProperty = DependencyProperty.Register("PopupInnerContentControlContentTemplate", typeof (DataTemplate), typeof (TaskBarIconProjectDemo), new PropertyMetadata(default(DataTemplate)));
    public static readonly DependencyProperty ButtonContentPropertyProperty = DependencyProperty.Register("ButtonContentProperty", typeof (object), typeof (TaskBarIconProjectDemo), new PropertyMetadata(default(object)));

    public TaskBarIconProjectDemo()
    {
        InitializeComponent();
    }

    public ICommand ButtonCommandProperty
    {
        get { return (ICommand) GetValue(ButtonCommandPropertyProperty); }
        set { SetValue(ButtonCommandPropertyProperty, value); }
    }

    public bool PopupIsOpenProperty
    {
        get { return (bool) GetValue(PopupIsOpenPropertyProperty); }
        set { SetValue(PopupIsOpenPropertyProperty, value); }
    }

    public object PopupInnerContentControlDataContext
    {
        get { return (object) GetValue(PopupInnerContentControlDataContextProperty); }
        set { SetValue(PopupInnerContentControlDataContextProperty, value); }
    }

    public DataTemplate PopupInnerContentControlContentTemplate
    {
        get { return (DataTemplate) GetValue(PopupInnerContentControlContentTemplateProperty); }
        set { SetValue(PopupInnerContentControlContentTemplateProperty, value); }
    }

    public object ButtonContentProperty
    {
        get { return (object) GetValue(ButtonContentPropertyProperty); }
        set { SetValue(ButtonContentPropertyProperty, value); }
    }
}

4。查看模型:

    public class DemoMainViewModel:BaseObservableObject
{
    private bool _isOpen;
    private TaskBarDemoViewModel _taskBarDemoViewModel;
    private ICommand _showPopupCommnad;

    public DemoMainViewModel()
    {
        TaskBarDemoViewModel = new TaskBarDemoViewModel(ClosePopup, "Here you can put your content. Go for it...");
    }

    private void ClosePopup()
    {
        IsPopupOpen = false;
    }

    public bool IsPopupOpen
    {
        get { return _isOpen; }
        set
        {
            _isOpen = value;
            OnPropertyChanged();
        }
    }

    public TaskBarDemoViewModel TaskBarDemoViewModel    
    {
        get { return _taskBarDemoViewModel; }
        set
        {
            _taskBarDemoViewModel = value;
            OnPropertyChanged();
        }
    }

    public ICommand ShowPopupCommand
    {
        get { return _showPopupCommnad ?? (_showPopupCommnad = new RelayCommand(ShowPopup)); }
    }

    private void ShowPopup()
    {
        IsPopupOpen = true;
    }
}

public class TaskBarDemoViewModel:BaseObservableObject
{
    private readonly Action _closePopupCommand;
    private ICommand _command;
    private string _textString;

    public TaskBarDemoViewModel(Action closePopupCommand, string content)
    {
        _closePopupCommand = closePopupCommand;
        TextString = content;
    }

    public ICommand PopupInnerButtonCommand
    {
        get { return _command ?? (_command = new RelayCommand(TargetMethod)); }
    }

    private void TargetMethod()
    {
        //add your logic here
        if(_closePopupCommand == null) return;
        _closePopupCommand();
    }

    public string TextString
    {
        get { return _textString; }
        set
        {
            _textString = value;
            OnPropertyChanged();
        }
    }
}

5。按钮样式(根据需要更改):

    <Color x:Key="ButtonLowerPartKey">#FFD5E0EE</Color>
    <Color x:Key="ButtonUpperPartKey">#FFEAF1F8</Color>
    <Color x:Key="PressedColorButtonLowerPartKey">#FFF4C661</Color>
    <Color x:Key="PressedButtonUpperPartKey">#FFF4CC87</Color>
    <Color x:Key="HooveredButtonLowerPartKey">#FFFFD06D</Color>
    <Color x:Key="HooveredButtonUpperPartKey">#FFFFF0DF</Color>
    <Style x:Key="SpecialButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
        <Setter Property="Padding" Value="5">
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid x:Name="Grid">
                        <Ellipse x:Name="ButtonControlBorder" Stroke="{TemplateBinding BorderBrush}" 
                                 StrokeThickness="{TemplateBinding BorderThickness}" 
                                 Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                            <Ellipse.Fill>
                                <LinearGradientBrush x:Name="BrushKey" MappingMode="RelativeToBoundingBox" SpreadMethod="Repeat" StartPoint="0.5,0" EndPoint="0.5,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStop Offset="0.5" Color="{StaticResource ButtonUpperPartKey}" />
                                        <GradientStop Offset="0.5" Color="{StaticResource ButtonUpperPartKey}" />
                                        <GradientStop Offset="0.5" Color="{StaticResource ButtonLowerPartKey}" />
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </Ellipse.Fill>
                        </Ellipse>
                        <Ellipse x:Name="Pressed" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Opacity="0">
                            <Ellipse.Fill>
                                <LinearGradientBrush x:Name="PressedBrushKey" MappingMode="RelativeToBoundingBox" SpreadMethod="Repeat" StartPoint="0.5,0" EndPoint="0.5,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStop Offset="0.5" Color="{StaticResource PressedButtonUpperPartKey}" />
                                        <GradientStop Offset="0.5" Color="{StaticResource PressedButtonUpperPartKey}" />
                                        <GradientStop Offset="0.5" Color="{StaticResource PressedColorButtonLowerPartKey}" />
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </Ellipse.Fill>
                        </Ellipse>
                        <Ellipse x:Name="InnerPressed" 
                                Width="{Binding ElementName=Pressed, Path=Width}" Height="{Binding ElementName=Pressed, Path=Height}" 
                                Stroke="DarkOrange" Opacity="0" StrokeThickness="1" SnapsToDevicePixels="True" Fill="Transparent"/>
                        <ContentPresenter Content="{TemplateBinding Button.Content}" HorizontalAlignment="Center" VerticalAlignment="Center">
                            <ContentPresenter.OpacityMask>
                                <VisualBrush Visual="{Binding ElementName=ButtonControlBorder}" />
                            </ContentPresenter.OpacityMask>
                        </ContentPresenter>
                        <Grid.Triggers>
                            <EventTrigger RoutedEvent="Mouse.MouseEnter">
                                <BeginStoryboard x:Name="MouseEnterStoryboard">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="BrushKey" Storyboard.TargetProperty="GradientStops[0].Color" From="{StaticResource ButtonUpperPartKey}" To="{StaticResource HooveredButtonUpperPartKey}" Duration="0:0:0.3" AutoReverse="False" />
                                        <ColorAnimation Storyboard.TargetName="BrushKey" Storyboard.TargetProperty="GradientStops[2].Color" From="{StaticResource ButtonLowerPartKey}" To="{StaticResource HooveredButtonLowerPartKey}" Duration="0:0:0.3" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="Mouse.MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="BrushKey" Storyboard.TargetProperty="GradientStops[0].Color" From="{StaticResource HooveredButtonUpperPartKey}" To="{StaticResource ButtonUpperPartKey}" Duration="0:0:1" AutoReverse="False" />
                                        <ColorAnimation Storyboard.TargetName="BrushKey" Storyboard.TargetProperty="GradientStops[2].Color" From="{StaticResource HooveredButtonLowerPartKey}" To="{StaticResource ButtonLowerPartKey}" Duration="0:0:1" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Grid.Triggers>
                    </Grid>
                    <ControlTemplate.Resources>
                        <Storyboard x:Key="MouseUpTimeLine">
                            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Pressed" Storyboard.TargetProperty="Opacity">
                                <SplineDoubleKeyFrame KeyTime="00:00:00.25" Value="0" />
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                        <Storyboard x:Key="MouseDownTimeLine">
                            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Pressed" Storyboard.TargetProperty="Opacity">
                                <SplineDoubleKeyFrame KeyTime="00:00:00.05" Value="0.8" />
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                        <Storyboard x:Key="InnerPressedMouseUpTimeLine">
                            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="InnerPressed" Storyboard.TargetProperty="Opacity">
                                <SplineDoubleKeyFrame KeyTime="00:00:00.25" Value="0" />
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                        <Storyboard x:Key="InnerPressedMouseDownTimeLine">
                            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="InnerPressed" Storyboard.TargetProperty="Opacity">
                                <SplineDoubleKeyFrame KeyTime="00:00:00.05" Value="1" />
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </ControlTemplate.Resources>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" SourceName="Grid" Value="True">
                            <Setter Property="Stroke" TargetName="ButtonControlBorder">
                                <Setter.Value>
                                    <SolidColorBrush Color="{StaticResource HooveredButtonLowerPartKey}">
                                    </SolidColorBrush>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="ButtonBase.IsPressed" Value="True">
                            <Trigger.EnterActions>
                                <BeginStoryboard Storyboard="{StaticResource MouseDownTimeLine}" />
                                <BeginStoryboard Storyboard="{StaticResource InnerPressedMouseDownTimeLine}">
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <BeginStoryboard Storyboard="{StaticResource MouseUpTimeLine}" />
                                <BeginStoryboard Storyboard="{StaticResource InnerPressedMouseUpTimeLine}">
                                </BeginStoryboard>
                            </Trigger.ExitActions>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
  1. BaseObservableObject是INCP的简单实现。

  2. RelayCommand是ICommand接口的简单实现

如果您对代码有疑问,我很乐意提供帮助。 此致,