如何在WPF中动态创建布局(MVVM模式)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在WPF中动态创建布局(MVVM模式)相关的知识,希望对你有一定的参考价值。
如何在WPF(MVVM模式)中动态创建布局?情景如下:
像摄像机查看器的应用程序,在启动时有一个主视图,屏幕顶部有一个带标签的按钮(“添加摄像头”),当添加摄像头时,它将显示在整个主屏幕,选择第二相机,屏幕应分为两部分,选择第三部相机后,屏幕应分为第三部分等。
怎么能在WPF中做到这一点?
答案
使用listview并将项目面板自定义为UniformGrid
<ListView ItemsSource="{Binding}" VerticalAlignment="Stretch" FlowDirection="LeftToRight" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid ClipToBounds="True"></UniformGrid>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate >
<Border BorderThickness="2">
<DockPanel Background="Red" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Id}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></TextBlock>
</DockPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
代码背后
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<Camera> cameraList = new ObservableCollection<Camera>();
public MainWindow()
{
InitializeComponent();
this.DataContext = cameraList;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
int sn = cameraList.Count + 1;
cameraList.Add(new Camera() { Id = sn.ToString()});
}
}
public class Camera
{
public string Id { get; set; }
}
另一答案
好的,这只是一个小例子。我使用了一个viewmodel,实现了InotifyPropertyChanged,一个带有Command binded的按钮,触发了网格的列。这是工作示例
- XAML
<Window x:Class="WpfApp2.MainWindow" 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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:local="clr-namespace:WpfApp2" mc:Ignorable="d" Title="MainWindow"> <Window.DataContext> <local:MyViewModel></local:MyViewModel> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition Height="50"/> <RowDefinition/> </Grid.RowDefinitions> <Button Grid.Row="0" Content="Add Camera" Command="{Binding AddCamera}" Margin="10" VerticalAlignment="Center" FontSize="15" Width="90" Height="26" FontWeight="DemiBold"/> <Grid Grid.Row="1"> <Grid.ColumnDefinitions > <ColumnDefinition > <ColumnDefinition.Style> <Style TargetType="{x:Type ColumnDefinition}"> <Setter Property="Width" Value="0" /> <Style.Triggers> <DataTrigger Binding="{Binding Camera1}" Value="True"> <Setter Property="Width" Value="*" /> </DataTrigger> </Style.Triggers> </Style> </ColumnDefinition.Style> </ColumnDefinition> <ColumnDefinition > <ColumnDefinition.Style> <Style TargetType="{x:Type ColumnDefinition}"> <Setter Property="Width" Value="0" /> <Style.Triggers> <DataTrigger Binding="{Binding Camera2}" Value="True"> <Setter Property="Width" Value="*" /> </DataTrigger> </Style.Triggers> </Style> </ColumnDefinition.Style> </ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Text=" CAMERA1" Width="100" HorizontalAlignment="Center" Height="100" Grid.Column="0"/> <TextBlock Text=" CAMERA2" Width="100" HorizontalAlignment="Center" Height="100" Grid.Column="1"/> </Grid> </Grid> </Window>
如你所见,我在内部网格中放置了2个文本块来表示你的“相机”
现在是viewmodel
-Viewmodel
namespace WpfApp2
{
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool camera1 = false;
private bool camera2 = false;
public bool Camera1
{
get { return camera1; }
set
{
camera1 = true;
NotifyPropertyChanged();
}
}
public bool Camera2
{
get { return camera2; }
set
{
camera2 = true;
NotifyPropertyChanged();
}
}
private RelayCommand addCamera;
private void Add()
{
if (Camera1 == false)
{
Camera1 = true;
}
else
Camera2 = true;
}
public ICommand AddCamera
{
get
{
addCamera = new RelayCommand(() => Add());
return addCamera;
}
}
}
}
如果你理解MVVM,你不应该对我上面提到的视图模型感到惊讶
as Extra是我用来实现命令的实用程序
-Relay命令
namespace WpfApp2
{
internal class RelayCommand<T> : ICommand
{
#region Fields
readonly Action<T> _execute = null;
readonly Predicate<T> _canExecute = null;
#endregion // Fields
#region Constructors
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
以上是关于如何在WPF中动态创建布局(MVVM模式)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MVVM 模式中从页面导航到 WPF 中的页面?没有棱镜的概念[重复]