【问题标题】:MVVM + WPF + Popup = cluelessMVVM + WPF + Popup = 无能为力
【发布时间】:2011-01-01 03:49:04
【问题描述】:

我仍在努力修改我现有的 WPF 应用程序以“兼容”MVVM 方法。我已经非常接近了,但不知道如何解决剩下的几个障碍之一。

我有一个 GUI 元素(目前是一个按钮,虽然它可能是一个标签),当鼠标进入它时,它会触发 MouseEnter 事件,这会在代码隐藏中创建一个弹出窗口。弹出窗口由一个带有几个按钮的简单堆栈面板布局组成。当前,每个按钮的 Click 事件都分配给同一个事件处理程序,除了我将 Tag 属性更改为执行一个简单(俗气的)命令参数。我正在与在 MVVM 中执行此操作的“正确”方法作斗争,因为我现在这样做的方式非常丑陋。

为了解决这个问题,我认为这是我应该前进的方向,但如果你能提供任何额外的意见,我将不胜感激。 :)

  1. 在 XAML 中创建弹出窗口。由于我的 Popup 内容是静态的,我应该能够完全在 XAML 中创建 Popup。此外,每个按钮都将绑定到同一个 ICommand 派生类。例如

    <Popup x:Key="MyPopup" StaysOpen="False" Placement="Right">
        <Border Background="White" BorderBrush="Black" Padding="5" BorderThickness="2" CornerRadius="5">
            <StackPanel Orientation="Vertical">
                <Button Command="{Binding MyCommand}" CommandParameter="5">5</Button>
                <Button Command="{Binding MyCommand}" CommandParameter="10">10</Button>
                <Button Command="{Binding MyCommand}" CommandParameter="15">15</Button>
                <Button Command="{Binding MyCommand}" CommandParameter="20">20</Button>
            </StackPanel>
        </Border>
    </Popup>
    
  2. 通过触发器弹出弹出窗口,例如

                            <Button.Triggers>
                                <Trigger Property="Button.IsMouseOver" Value="True">
                                    <Setter TargetName="MyPopup" Property="IsOpen" Value="True" />
                                </Trigger>
                            </Button.Triggers>
    

我认为 #1 没问题,但我在 #2 上苦苦挣扎。这是解决问题的正确方法吗?如果是这样,将 Popup 的 IsOpen 属性设置为 True 的正确 XAML 语法是什么?我找不到这方面的例子。

如果我的整个想法有缺陷,我很想听听我的其他选择是什么。谢谢!

【问题讨论】:

  • 我看不出你的 #2 有什么问题,也许你可以提供更多关于你认为有问题的细节。
  • 我收到错误消息“'IsOpen' 成员无效,因为它没有合格的类型名称。”
  • 我也试过 Popup.IsOpen 并得到同样的错误。

标签: wpf mvvm popup


【解决方案1】:

这就是我要做的,首先我将我的可重用部分分成资源,并在 XAML 中使用 ContentControls 引用它们。这适用于Popup 以及Button。但是我不想限制自己只有一个按钮,所以我也会使用ContentControl:

弹出式模板:

<ControlTemplate x:Key="PopupTemplate">
    <Border 
                Background="White" 
                BorderBrush="Black" 
                Padding="5" 
                BorderThickness="2" 
                CornerRadius="5">
        <StackPanel Orientation="Vertical">
            <Button Command="{Binding MyCommand}" 
                            CommandParameter="5">5</Button>
            <Button Command="{Binding MyCommand}" 
                            CommandParameter="10">10</Button>
            <Button Command="{Binding MyCommand}" 
                            CommandParameter="15">15</Button>
            <Button Command="{Binding MyCommand}" 
                            CommandParameter="20">20</Button>
        </StackPanel>
    </Border>
</ControlTemplate>

ContentControl 模板:

<ControlTemplate x:Key="MyControlTemplate" TargetType="ContentControl">
    <Grid Name="MyControl">
        <ContentPresenter Content="{TemplateBinding Content}"/>
        <Popup Name="MyPopup" StaysOpen="True" Placement="Bottom">
            <ContentControl Template="{StaticResource PopupTemplate}"/>
        </Popup>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger SourceName="MyControl" 
                 Property="UIElement.IsMouseOver" 
                 Value="True">
            <Setter TargetName="MyPopup" 
                    Property="Popup.IsOpen" 
                    Value="True"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

现在在主窗口 XAML 中,我将创建以下内容:

<ContentControl Template="{StaticResource MyControlTemplate}">
    <Button Content="Test"/>
</ContentControl>

如果您有任何问题,我很乐意为您解答。

【讨论】:

  • 感谢您的帮助!这听起来确实是一个不错的方向。我会告诉你进展如何!
  • 它几乎可以工作了!我现在唯一的问题是,当我单击 GUI 中的其他位置时,弹出窗口消失(这是我想要的),但是当我再次将鼠标悬停在 ContentControl 上时,弹出窗口不再出现。我是否必须在另一个触发器中将 IsOpen 显式设置为 False?理想情况下,如果我单击某个不是 Popup 或 ContentControl(即某种复合/多触发器)的位置,我会让 Popup 消失。
  • 我认为问题可能是您在某处明确将IsOpen 设置为false,从而覆盖了触发器。您是否在代码隐藏中执行此操作?也许在弹出按钮中命令绑定的处理程序中?如果是这样,您需要清除其值以重新启用触发器......这可能很棘手。
  • 我没有在代码隐藏的任何地方将 IsOpen 设置为 False,但我确实将 StaysOpen 属性设置为 False,因为我希望它在我单击其他地方时消失。我已经忘记了。那么我是否应该将 StaysOpen 设置为 True,然后添加一个 MultiTrigger 将 IsOpen 设置为 False?
  • 好的,我只是继续尝试,结果不是我所期望的。如果我将 StaysOpen 设置为 True,然后添加 MultiTrigger,它会按预期运行,但如果我从 ContentControl 移动到 Popup 的速度太慢,则 Popup 会消失。有趣的是,如果我只是将 StaysOpen 设置为 True 并且 不 实现 MultiTrigger,则行为完全相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
  • 1970-01-01
相关资源
最近更新 更多