wpf mvvm方式实现动态添加按钮

网上找到的例子里代码有缺失,参照找到的例子用prism框架做了个demo,做个记录。

MultiPageSample.xaml("主窗口"):

<Window x:Class="BlankApp1.Views.MultiPageSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BlankApp1.Views"
        mc:Ignorable="d"
        Title="MultiPageSample" Height="450" Width="800">
    <UniformGrid Rows="1" Columns="2">
        <local:Page1 DataContext="{Binding Page1, Mode=TwoWay}"/>
        <local:Page2 DataContext="{Binding Page2,Mode=TwoWay}"/>
    </UniformGrid>
</Window>

MultiPageSample对应后台代码

    public partial class MultiPageSample : Window
    {
        public MultiPageSample()
        {
            InitializeComponent();
        }
    }

MultiPageSample视图模型:

    public class MultiPageSampleViewModel : BindableBase
    {
        public Page1ViewModel Page1 { get; set; }

        public Page2ViewModel Page2 { get; set; }

        public MultiPageSampleViewModel()
        {
            Page1 = new Page1ViewModel();
            Page2 = new Page2ViewModel();

            Page2.AddNewCommand = new Command(Page1.AddCommand);
        }
    }

Page1:

<UserControl x:Class="BlankApp1.Views.Page1"
             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" 
             xmlns:viewmodels="clr-namespace:BlankApp1.ViewModels" 
             d:DataContext="{d:DesignInstance Type=viewmodels:Page1ViewModel}"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <ItemsControl ItemsSource="{Binding Commands, Mode=TwoWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Command="{Binding Click}" Content="{Binding Name}"
                        Margin="2" Name="btn"  >
                </Button>
                <DataTemplate.Triggers>
                    <DataTrigger  Binding="{Binding SelectedFlag, Mode=TwoWay}" Value="True">
                        <Setter TargetName="btn" Property="Foreground" Value="Red"></Setter>
                    </DataTrigger>
                    <DataTrigger  Binding="{Binding SelectedFlag, Mode=TwoWay}" Value="False">
                        <Setter TargetName="btn" Property="Foreground" Value="Blue"></Setter>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
            
        </ItemsControl.ItemTemplate>
        
    </ItemsControl>
</UserControl>

Page1 对应后台代码:

    public partial class Page1 : UserControl
    {
        public Page1()
        {
            InitializeComponent();
        }
    }

Page1 视图模型::

    public class Page1ViewModel : BindableBase
    {
        public Page1ViewModel()
        {
            Commands = new ObservableCollection<Command>();
            Command cmd = new Command(FirstAction);
                cmd.SelectedFlag = false;
            cmd.Name = "inited1";
            Commands.Add(cmd);
            cmd = new Command(FirstAction);
            cmd.Name = "inited2";
            Commands.Add(cmd);
        }

        public ObservableCollection<Command> _command;
        public ObservableCollection<Command> Commands
        {
            get => _command;
            set { SetProperty(ref _command, value); }
        }

        public void AddCommand()
        {
            Command cmd = new Command(FirstAction);
            cmd.Name = "added";
            Commands.Add(cmd);
            MessageBox.Show(Commands.Count.ToString());
        }

        private void FirstAction()
        {
            // do first Action;
            //MessageBox.Show("name");
            Command cmd = new Command();
            cmd.Name = "added";
            Commands.Add(cmd);
            MessageBox.Show(Commands.Count.ToString());
        }
    }

Page2:

<UserControl x:Class="BlankApp1.Views.Page2"
             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" 
             xmlns:local="clr-namespace:BlankApp1.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Button Content="Add New Command (I Mean Button)"
            VerticalAlignment="Center" HorizontalAlignment="Center"
            Command="{Binding AddNewCommand}"/>
</UserControl>

Page2 对应后台代码:

    public partial class Page2 : UserControl
    {
        public Page2()
        {
            InitializeComponent();
        }
    }

Page2 视图模型::

    public class Page2ViewModel : BindableBase
    {
        public Command AddNewCommand { get; set; }
    }

Command 类:

    public class Command : BindableBase, ICommand
    {
        public Action Action { get; set; }

        public void Execute(object parameter)
        {
            if (Action != null)
                Action();
        }

        public ICommand Click
        {
            get => new DelegateCommand(() =>
            {
                SelectedFlag = !SelectedFlag;
                MessageBox.Show(Name+" clicked!"+ SelectedFlag.ToString());
            });
        }

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

        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }

       

        private bool _isSelected = true;
        public bool SelectedFlag
        {
            get => _isSelected;
            set { SetProperty(ref _isSelected, value); }
        }

        private string _name = "";
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
            }
        }

        public event EventHandler CanExecuteChanged;

        public Command(Action action)
        {
            Action = action;
        }

        public Command()
        {

        }
    }

    public class Command<T> : ICommand
    {
        public Action<T> Action { get; set; }

        public void Execute(object parameter)
        {
            if (Action != null && parameter is T)
                Action((T)parameter);
        }

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

        private bool _isEnabled;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler CanExecuteChanged;

        public Command(Action<T> action)
        {
            Action = action;
        }

        public Command()
        {

        }

    }

里面完全抛弃了在代码中操作UI元素的传统心态,用mvvm实现。

里面知识涉及ItemsControl的使用,Command类定义等。

功能逻辑大概说明:

1. 在Page1中用其自动遍历绑定的视图模型中Commands变量,实现动态生成控件,需注意Commands变量类型需为ObservableCollection。

2. 同时用WrapPanel实现控件自动排布。

3. 额外加了触发器实现点击按钮后样式的变更。里面用到了自定义的属性SelectedFlag。

4. 另外按钮的点击事件,如果只是用例子中的 Command="{Binding}",则是用的新建实例时绑的action,也可以另外绑定定义的方法,在这用了command中定义的Click方法,Command="{Binding Click}"。

参考资料:

如何动态地将控件添加到另一个类的WrapPanel中? | (1r1g.com)

Command模式的C#简单实现 - 柚子Nan - 博客园 (cnblogs.com)

WPF TextBlock 根据Text值,改变字体颜色_orangapple的博客-CSDN博客_textblock字体颜色

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: WPF(Windows Presentation Foundation)是一种用于创建可扩展的Windows桌面应用程序的框架。MVVM(Model-View-ViewModel)是一种用于实现分离用户界面与业务逻辑的模式。DataGrid是WPF中的一个常用控件,用于显示和编辑表格数据。 在WPF中,使用MVVM模式可以有效地将数据与视图分离。而DataGrid提供了一种简便的方式来显示和编辑表格数据。一个常见的场景是需要在DataGrid中显示动态的列,即根据一些条件或数据的变化来动态添加或删除列。 要实现DataGrid的动态列,可以通过绑定DataGrid的ItemsSource属性到一个集合类型的属性,该集合包含了要显示的表格数据。然后通过在ViewModel中动态改变该集合中的属性来添加或删除列。例如,可以使用ObservableCollection作为集合类型,该类型会自动通知DataGrid进行更新。 在XAML中,可以使用DataGrid的Columns属性来定义DataGrid的列。可以通过DataGridTemplateColumn定义一个模板列,然后在该模板列中绑定到动态的列数据。例如,可以使用ItemsControl来显示动态的列数据。 在ViewModel中,可以通过返回一个集合类型的属性来实现动态列的添加或删除。当需要添加或删除列时,只需要改变该属性的值,并通知视图进行更新。 总结来说,要实现WPF MVVM DataGrid的动态列,可以通过绑定DataGrid的ItemsSource属性到一个包含动态列数据的集合属性,然后动态改变该集合属性的值来实现动态列的添加或删除。在XAML中使用DataGridTemplateColumn来定义模板列,并在ViewModel中返回集合属性以实现动态列的变化。这样可以有效地实现表格列的动态调整。 ### 回答2: WPF MVVM(Model-View-ViewModel)是一种设计模式,它将UI(视图)与业务逻辑(模型)分离,通过ViewModel来进行交互和数据绑定。而DataGrid是WPF中用于显示和编辑数据的控件,它可以绑定到一个集合,并显示其中的数据。现在我们来谈谈如何实现动态列的DataGrid。 要实现动态列的DataGrid,我们需要以下几个步骤: 1. 定义数据源:我们需要有一个数据源,它会提供要显示的数据,这个数据可以是一个集合对象,并且集合中的对象需要有属性与列名对应。 2. 动态列生成:在ViewModel中,我们需要使用ObservableCollection来存储列的数据,例如列的名称、类型等。可以通过在ViewModel中的构造函数中添加逻辑来添加或删除需要的列。这样,在DataGrid中使用ItemsSource绑定到ObservableCollection的对象时,DataGrid会根据ObservableCollection的变化来生成动态列。 3. 利用DataTemplate生成动态列:使用AutoGeneratingColumn事件,可以在DataGrid生成列时拦截,我们可以在这个事件中使用DataTemplate来自定义生成的列,例如可以根据列的名称或类型来生成不同的列样式,也可以调整列的宽度等。 4. 利用绑定将数据填充到动态列中:通过给DataGrid中的每一列添加绑定,可以将数据源中的数据填充到动态列中。你可以使用Binding.Path来指定到数据源中的属性,以确保每列都显示正确的数据。 总的来说,实现动态列的DataGrid需要在ViewModel中使用ObservableCollection来存储列的数据,利用DataTemplate来生成动态列,并使用绑定将数据填充到列中。通过配合使用MVVM和DataGrid的相关特性,我们可以轻松实现具有动态列的DataGrid控件。 ### 回答3: WPF(Windows Presentation Foundation)是一个用于创建Windows应用程序的框架,而MVVM(Model-View-ViewModel)是一种设计模式,用于有效地将UI(用户界面)和业务逻辑分离。在WPF中,DataGrid是一种常用的控件,用于显示和编辑数据。 DataGrid可以根据数据源的结构自动创建列,但有时候我们可能需要动态添加或删除列。在MVVM模式下,我们可以使用绑定和命令来实现动态列。 首先,我们需要在ViewModel中定义一个集合(ObservableCollection)来绑定DataGrid的ItemsSource属性,这个集合需要包含动态列所需的数据。然后,我们可以在XAML中使用DataGrid控件,并将其ItemsSource绑定到ViewModel中定义的集合。 接下来,我们可以使用DataGrid的AutoGeneratingColumn事件来自定义动态列的生成。通过订阅这个事件,我们可以在列生成之前对其进行修改。例如,我们可以根据特定条件动态地给列设置样式或添加其他元素。 另外,如果我们需要在运行时添加或删除列,我们可以使用DataGrid.Columns属性。我们可以在ViewModel中定义一个命令,并将其绑定到按钮或其他触发动作的控件上。在命令执行时,我们可以通过修改DataGrid.Columns集合来添加或删除列。 总结起来,通过结合WPFMVVM和DataGrid,我们可以实现动态列的显示和编辑。使用绑定和命令,我们可以根据需要动态添加、修改或删除列,从而实现灵活的数据展示和用户交互。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值