Caliburn.Micro如何绑定元素的可见性到ViewModel的函数而不是属性?

4
首先,如果这是一个重复的问题,我很抱歉 - 我已经找了一段时间,但找不到答案。
我们正在使用caliburn.micro,所以解决方案必须使用这个工具。
我们有一个视图,由9个按钮组成,但是并非所有按钮都会同时可见,这取决于系统上的事件。每个按钮的可见性基于当前状态,要么为可见,要么为折叠,但由于按钮数量很大,并且可能在未来增加,我宁愿使用单个函数来完成此操作(接收名称或枚举并返回可见性),而不是将每个按钮绑定到大量属性。
这是一个选项吗?我似乎找不到任何常规方法来做到这一点。
由于事件是从我们正在开发的软件外部接收到的,因此在视图级别执行此操作实际上并不是一个选项(或者至少不是正确的选项)。
编辑:以下是我想修改的视图片段:
            <Grid Margin="0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>

                <uiviews:PhonePadView Grid.Column="0" x:Name="DestinationDn" cal:Bind.Model="UI.ViewModels.PhonePadViewModel" />

                <Button  Grid.Column="1" Content="Dial" Style="{StaticResource PhonePadBasicFunctionsButtons}" x:Name="MakeCall" Visibility="{Binding btnMakeCallVisibility}" />
                <Button  Grid.Column="1" Content="Answer" Style="{StaticResource PhonePadBasicFunctionsButtons}" x:Name="AnswerCall" Visibility="{Binding btnAnswerCallVisibility}" />
                <Button  Grid.Column="1" Content="Hang-up" Style="{StaticResource PhonePadBasicFunctionsButtons}" x:Name="ReleaseCall" Visibility="{Binding btnReleaseCallVisibility}" />
                <Button  Grid.Column="1" Content="Hold" Style="{StaticResource PhonePadBasicFunctionsButtons}" x:Name="HoldCall" Visibility="{Binding btnHoldCallVisibility}" />

            </Grid>

正如您所看到的,我需要为每个按钮设置不同的属性,我拒绝相信这是唯一的方法。我确实有一个持有当前状态(电话正在响铃、通话中、拨号等)的属性,并且在VM上轻松地拥有一个函数告诉哪个按钮应该可见,哪个不应该可见。此外,我们目前有9个按钮,但很容易扩展更多,因此我在寻找最模块化的代码。

1
你是否考虑过拥有9个(子)ViewModel实例并构建相应的1按钮视图? - H H
1
我怀疑你的问题可以通过将其分成带有1个按钮的UserControl来解决。但是,如果没有看到任何代码,很难具体说明。 - H H
1
发布的代码没有太大问题,XAML只是一种不太紧凑的语言。但是你应该通过BooleanToVisibility转换器绑定到布尔属性。 - H H
1
由于Caliburn的存在,启用/禁用变得更加容易,只需添加CanMakeCall属性即可。也许自定义约定还可以让您对可见性进行操作,但我不确定。 - H H
1
如果按钮的可见性逻辑不是很复杂,为什么不使用ConverterMultiValueConverter来决定可见性呢?如果只有ViewModel可以根据复杂状态来决定这些内容,那么尝试将其减少到一个计算属性或两个计算属性,例如CurrentVisibleButtonGroup,并将其设置为枚举或数字。基于该属性,使用简单的值转换器来决定哪些按钮应该可见。 - Mat J
显示剩余7条评论
2个回答

16

开箱即用,如果您使用“IsVisible”后缀为某个组件命名,Caliburn Micro将切换其可见性。

在视图中:

<Grid Name="ConfigEditorIsVisible">
    <TextBlock>Test</TextBlock>
</Grid>

关于ViewModel:

public bool ConfigEditorIsVisible { get; set; }

3
答案正确,只需澄清一下:必须放在网格或堆栈面板上(我猜测可以是流式面板),而不能直接放在控件上,应该将控件放入容器中。 - Adrián Alvarez

0

所以...最终我做了这个: 在虚拟机上:

    private HashSet<string> actionsEnabledSet = null;
    public HashSet<string> ActionsEnabledSet
    {
        get { return actionsEnabledSet; }
        set
        {
            actionsEnabledSet = value;
            NotifyOfPropertyChange(() => ActionsEnabledSet);
        }
    }

我想要更改哈希集合以显示所需的项目。

具有转换功能的(多)转换器:

    public object Convert(object[] value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
    {
        if (value[0].GetType() == typeof(HashSet<string>))
        {
            if (value[1].GetType() == typeof(string))
            {
                if (((HashSet<string>)value[0]).Contains((string)value[1]))
                    return Visibility.Visible;
            }
        }
        return Visibility.Collapsed;
    }

查看按钮样式:(尽可能避免重复代码)

    <Style TargetType="Button" x:Key="PhonePadBasicFunctionsButtons" >
        <Setter Property="Margin" Value="0,0,0,0" />
        <Setter Property="Focusable" Value="False" />
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="Width" Value="75" />
        <Setter Property="Visibility">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource PhoneActionVisibilityConverter1}">
                    <Binding Path="ActionsEnabledSet" Mode="OneWay"/>
                    <Binding RelativeSource="{RelativeSource Self}" Path="Tag" />
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>

还有一个按钮的堆栈面板,看起来像这样:

                <Button  Content="Call" Style="{StaticResource PhonePadBasicFunctionsButtons}" x:Name="MakeCall" Tag="MakeCall" cal:Message.Attach="MakeCall" />
                <Button  Content="Answer" Style="{StaticResource PhonePadBasicFunctionsButtons}" x:Name="AnswerCall" Tag="AnswerCall" cal:Message.Attach="AnswerCall" />

真的很烦恼,我找不到一种将“tag”绑定到“x:name”的方法,但添加新按钮就像添加一行代码那样容易,这样编码感觉更好,希望能有任何关于如何改进它的想法,我认为它很优雅,但我有一种感觉它可能更容易阅读/实现。

我不得不使用多绑定,因为使用转换器属性不是一个选项 - 似乎你不能将元素绑定到属性,希望这对未来的某个人有所帮助 - 这是一个不错的挑战 :)

感谢每个试图帮助我的人 - 你们让我走出了我的舒适区并寻找答案!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接