网上找到的例子里代码有缺失,参照找到的例子用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字体颜色