wpf 如何使用xaml控件显示/隐藏其他控件?

eh57zj3b  于 2023-01-14  发布在  其他
关注(0)|答案(3)|浏览(466)

我在xaml中有一个组合框,它向用户提供1、2和3作为选项。

<ComboBox x:Name="cbNoOfChoices" Text="{Binding Path = NoOfChoices, Mode=OneWayToSource}" >
            <ComboBoxItem>1</ComboBoxItem>
            <ComboBoxItem>2</ComboBoxItem>
            <ComboBoxItem>3</ComboBoxItem>
    </ComboBox> 
        
    <Label x:Name="lblNo1" Content="Number 1" ></Label>
        <TextBox x:Name="txtbxNo1" Text="{Binding Path = No1, Mode=OneWayToSource}"/>

     <Label x:Name="lblNo2" Content="Number 2" ></Label>
        <TextBox x:Name="txtbxNo2" Text="{Binding Path = No2, Mode=OneWayToSource}"/>
   
     <Label x:Name="lblNo3" Content="Number 3" ></Label>
        <TextBox x:Name="txtbxNo3" Text="{Binding Path = No3, Mode=OneWayToSource}"/>

两个问题:
1.如果选择0,则只有标签"数字1"及其关联文本框必须可见。如果选择1,则只有标签"数字1"和标签"数字2"及其关联文本框必须可见,以此类推。如何操作?
1.也有不同的公式正在使用取决于组合框的选择。不知道如何提取组合框的选择,以指定使用哪个公式。将一个属性本身的工作?
公有双精度NoOfChoices {get {return NoOfChoices;}

set
        {
            noOfChoices = value;
        }
    }

上述值是否为组合框选项?
谢谢。

jv2fixgn

jv2fixgn1#

问:“使用(..)控件显示/隐藏其他控件?"
这看起来像是anti-pattern。当你需要隐藏一个编辑控件时,设置它的Visibility属性。

myEdit.Visibility = Visibility.Hidden;
                    // Visibility.Collapsed;
                    // Visibility.Visible;

你可以对它的标题标签做同样的事情。当你想隐藏的组件有多个时,把它们放在一个面板容器中,然后隐藏面板。
在WPF中使用可观察对象、标记和绑定,参考这些其他SO问题,
Elegant way to change control visibility in wpf
Want to show/hide control from ViewModel in wpf
..它指的是MSDN - How to: Implement Property Change Notification

bakd9h0s

bakd9h0s2#

我能想到的MVVM解决方案是:

  • 实现ValueConverter,将整数(或双精度)转换为Visibility,并接受一个参数值,当转换后的值等于该参数时,返回值为Visibility.Visible,在所有其他情况下返回值为Visibility.Collapsed
  • 对于所有标签(lblNo1lblNo2等),使用前面实现的值转换器将其Visibility绑定到组合框SelectedIndex属性,并给出相应的参数。

如果你明白了就告诉我。如果不明白,我会试着准备一些代码。

编辑

新的一天,新的能量,我为你准备了一些代码。
您可以通过以下方式开始值转换器的实现:

[ValueConversion(typeof(int), typeof(bool))]
public class IntEqualsToBooleanConverter : IValueConverter
{
    /// <summary>
    /// Converts integer value to bool (is value equal to the parameter)
    /// </summary>
    /// <param name="value">The value determining the output</param>
    /// <param name="targetType">Target type onto which the value is converted (must be bool)</param>
    /// <param name="parameter">Determining value - if the value is equal to, output is true</param>
    /// <param name="culture">Culture info</param>
    /// <returns>Returns true if the value is equal to the parameter</returns>
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int determinant = 0;

        if (targetType != typeof(bool) && targetType != typeof(Object))
            throw new InvalidOperationException("The target must be a boolean");

        if (parameter == null) 
        {
            return false;
        }
        else if (parameter is int)
        {
            determinant = (int)parameter;
        }
        else if (!(parameter is string && int.TryParse(parameter as string, out determinant)))
            throw new ArgumentException("The converter parameter must be an integer or a string representing integer");

        return (int)value == determinant;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

然后,在xaml中,将此转换器作为资源添加,在我的测试中,它只是一个窗口,我在local:命名空间中添加了ValueConverter实现:

<Window.Resources>
    <local:IntEqualsToBooleanConverter x:Key="IntToBoolConverter" />
</Window.Resources>

最后,您的ComboBox和您想要灰显的项目可能如下所示-检查标签的IsEnabled绑定:

<StackPanel Orientation="Vertical">
    <ComboBox Width="100" HorizontalAlignment="Left" x:Name="SelectionCombo">
        <ComboBoxItem Content="Item 0" IsSelected="True" />
        <ComboBoxItem Content="Item 1" />
        <ComboBoxItem Content="Item 2" />
    </ComboBox>
    <StackPanel Orientation="Horizontal">
        <Label Content="Label 0" IsEnabled="{Binding ElementName=SelectionCombo, Path=SelectedIndex, Converter={StaticResource IntToBoolConverter}, ConverterParameter=0}" />
        <Label Content="Label 1" IsEnabled="{Binding ElementName=SelectionCombo, Path=SelectedIndex, Converter={StaticResource IntToBoolConverter}, ConverterParameter=1}" />
        <Label Content="Label 2" IsEnabled="{Binding ElementName=SelectionCombo, Path=SelectedIndex, Converter={StaticResource IntToBoolConverter}, ConverterParameter=2}" />
    </StackPanel>
</StackPanel>

如果你希望标签(或其他控件)在不活动时完全消失,那么实现另一个值转换器,其中Visibility是返回类型,Convert方法的最后一行是:

return ((int)value == determinant) ? Visibility.Visible : Visibility.Collapsed;

并且绑定到标签的Visibility属性,而不是IsEnable

vxqlmq5t

vxqlmq5t3#

下面是一个使用社区mvvm工具包的示例。
主窗口

Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <DockPanel LastChildFill="True">
        <ComboBox  DockPanel.Dock = "Top" 
                   ItemsSource="{Binding Options}"
                   SelectedItem="{Binding SelectedArrayOption}"
                   DisplayMemberPath="DisplayName"
                   />
        <ItemsControl ItemsSource="{Binding Cells}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Rows="5"
                                 Columns="5"
                                 FlowDirection="LeftToRight"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Description}"/>
                        <TextBox Text="{Binding Num}"
                                 Grid.Column="1"/>

                        <Rectangle Grid.ColumnSpan="2"
                                   Fill="LightGray"
                                   Opacity=".4">
                            <Rectangle.Style>
                                <Style TargetType="Rectangle">
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding IsActive}" Value="False">
                                            <Setter Property="Visibility" Value="Visible"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Rectangle.Style>
                        </Rectangle>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </DockPanel>
</Window>

我用一个矩形把整个单元格变灰了。你可以用一个booleantovisibilityconverter来绑定可见性。你需要一个外部面板来保留,否则单元格会移动。另一个选择是隐藏停靠面板,但是你需要写一个booltoHide转换器。
主窗口视图模型

public partial class MainWindowViewModel : ObservableObject
    {

        private CellVM[,] matrixCells = new CellVM[5, 5];

        [ObservableProperty]
        private List<CellVM> cells= new List<CellVM>();

        [ObservableProperty]
        private List<ArrayOptionVM> options = new List<ArrayOptionVM>
        {
            new ArrayOptionVM{ DisplayName = "1", MaxLimit= 3},
            new ArrayOptionVM{ DisplayName = "2", MaxLimit= 4},
            new ArrayOptionVM{ DisplayName = "3", MaxLimit= 5}
        };

        private ArrayOptionVM? selectedArrayOption;
        public ArrayOptionVM? SelectedArrayOption
        { get => selectedArrayOption; 
        set 
            {
                SetProperty(ref selectedArrayOption, value);
                setActiveCells(selectedArrayOption.MaxLimit);
            } 
        }

        private void setActiveCells(int maxLimit)
        {
            for (int x = 0; x < 5; x++)
            {

                for (int y = 0; y < 5; y++)
                {
                    matrixCells[x, y].IsActive = x < maxLimit && y < maxLimit;
                }
            }
        }
        public MainWindowViewModel() 
        {
            for (int x = 0; x < 5; x++)
            {
                for (int y = 0; y < 5; y++)
                {
                    var cell = new CellVM { Description= $"{x},{y}" };
                    matrixCells[x, y] = cell;
                    cells.Add(cell);
                }
            }
        }
    }

选择一个ArrayOptionVM会使用一个setter调用的方法来驱动灰色的内容,这会使setter的速度慢一点,所以如果你要做大量的处理,你会希望在不同的线程上执行任务。
为了处理方便,CellVM的每个示例都被添加到2d数组和列表中。
ArrayOptionVM定义组合框项

public partial class ArrayOptionVM : ObservableObject
{
    public int MaxLimit = 3;

    [ObservableProperty]
    private string displayName = string.Empty;

}

Maxlimit在某种程度上抽象了选中活动单元格时的最大范围。
CellVM是每个单元背后的视图模型

public partial class CellVM : ObservableObject
{
    [ObservableProperty]
    private string description = string.Empty;

    [ObservableProperty]
    private int? num;

    [ObservableProperty]
    private bool isActive;
}

显然,这里有选择,绝对有改进的空间。
下面是主窗口绑定可见性的一个版本。

Title="MainWindow" Height="450" Width="800">
   <Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <DockPanel LastChildFill="True">
        <ComboBox  DockPanel.Dock = "Top" 
                   ItemsSource="{Binding Options}"
                   SelectedItem="{Binding SelectedArrayOption}"
                   DisplayMemberPath="DisplayName"
                   />
        <ItemsControl ItemsSource="{Binding Cells}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Rows="5"
                                 Columns="5"
                                 FlowDirection="LeftToRight"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                <Grid>
                    <Grid Visibility="{Binding IsActive, Converter={StaticResource BooleanToVisibilityConverter}}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Description}"/>
                        <TextBox Text="{Binding Num}"
                                 Grid.Column="1"/>
                    </Grid>
                </Grid>
            </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </DockPanel>
</Window>

相关问题