如何在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模式)的主要内容,如果未能解决你的问题,请参考以下文章

WPF 如何将主题应用于使用 MVVM 动态创建的对象

WPF MvvM DataGrid 动态列

wpf mvvm模式 Icommand接口应该如何理解?

如何在 MVVM 模式中从页面导航到 WPF 中的页面?没有棱镜的概念[重复]

WPF 在 MVVM 模式下实现窗口后台代码与ViewModel交互

使用 MVVM 在 WPF 中创建新窗口的最佳方法