首页 > 解决方案 > 动态控制可见性 WPF MVVM C#

问题描述

我有一个列表框,下面有几个按钮。

<ListBox ItemsSource="{Binding SongList}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=.}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
<StackPanel Orientation="Horizontal">
    <Button Content="Add" Command="{Binding addSongCommand}" />
    <Button Content="Remove"/>
</StackPanel>

歌曲列表1

当我单击添加按钮时,我希望将添加和删除按钮替换为文本框并提交按钮。

歌曲列表2

然后,当我单击提交时,我希望它将输入的字符串添加到集合(SongList)中并带回添加和删除按钮。

歌曲列表3

如何使用 MVVM 完成控件的隐藏和显示?假设我可以在 addSongCommand.Execute() 方法中访问这个视图视图模型,我会在那里放置什么逻辑?

public class AddSongCommand : CommandBase
{

    private ViewModelBase _vm;

    public AddSongCommand(ViewModelBase vm)
    {
        _vm = vm;
    }

    public override bool CanExecute(object parameter) => true;

    public override void Execute(object parameter)
    {
        // what goes here?
    }
}

标签: c#wpf

解决方案


<ListBox ItemsSource="{Binding SongList}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=.}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<StackPanel Orientation="Horizontal" Visibility="{Binding IsAdding, Converter={booltovisflipconverter}}">
    <Button Content="Add" Command="{Binding AddSongCommand}" />
    <Button Content="Remove"/>
</StackPanel>

<StackPanel Orientation="Vertical" Visibility="{Binding IsAdding, Converter={booltovisconverter}}">
    <TextBox Text="{Binding Song}"/>
    <Button Content="Submit" Command="{Binding SubmitSongCommand}" />
</StackPanel>

注意:您需要编写转换器来翻转可见性,或使用数据触发器。

public class ViewModel : ViewModelBase
{  
    public ObservableCollection<string> SongList {get;set;} = new ObservableCollection<string>();
    
    public bool IsAdding
    {
       get { ... }
       set { notifychanged }
    }

    public string Song 
    {
       get { ... }
       set { notifychanged }
    }

    // called from add song command
    public void EnableAdding()
    {
        IsAdding = true;
    }

    // called from submit command
    public void SubmitSong()
    {   
        SongList.Add(Song);
        IsAdding = false;
    }
}

public class SubmitSongCommand : CommandBase
{    
    private ViewModel _vm;

    public SubmitSongCommand(ViewModel vm)
    {
        _vm = vm;
    }

    public override bool CanExecute(object parameter) => true;

    public override void Execute(object parameter)
    {
        _vm.SubmitSong();
    }
}


public class AddSongCommand : CommandBase
{    
    private ViewModel _vm;

    public AddSongCommand(ViewModel vm)
    {
        _vm = vm;
    }

    public override bool CanExecute(object parameter) => true;

    public override void Execute(object parameter)
    {
        _vm.EnableAdding();
    }
}

上面为每个命令使用了特定的类型。这么多命令=许多类型。您可以改为使用委托来实现基本命令。

public class SimpleCommand : ICommand 
{
    public Action<object> ExecuteAction {get;set;}

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        ExecuteAction?.Invoke(parameter);
    }
}

public class ViewModel
{
    public ViewModel()
    {
        AddSongCommand  = new SimpleCommand()
        {
             ExecuteAction = (x) => { AddSong(); }
        };

        SubmitSongCommand = new SimpleCommand()
        {
            ExecuteAction = (x) => { SubmitSong(); }
        };
    }

    public ICommand AddSongCommand { get; }

    public ICommand SubmitSongCommand { get; }

    public void AddSong()
    {
        // add song to list
    }

    public void SubmitSong()
    {
        // submit song
    }
}

推荐阅读