自定义数据绑定到多个WPF C#

时间:2016-03-03 09:35:02

标签: wpf combobox stackpanel

我有一个XAML文件有两件事,

  1. 组合框

  2. 堆叠面板

  3. 如何使组合框中的更改自动使堆栈面板从一个堆栈面板切换到另一个堆栈面板。

    我的comboBox就像

    <ComboBox x:Name="MCbConnect" SelectedIndex="{Binding EnConnectionType}" Loaded="m_cbConnect_Loaded" SelectionChanged="m_cbConnect_SelectionChanged" Width="100"></ComboBox>
    

    其中EnConnectionType是这样的属性

    private ConnectionType _enConnectionType;
        public ConnectionType EnConnectionType
        {
            get { return _enConnectionType; }
            set { SetProperty(ref _enConnectionType, value, "EnConnectionType");  }
        }
    

    ConnectionType是

    public enum ConnectionType { Rs232 = 0, Can = 1, Ethernet = 2 };
    

    所以我已经在这里实现了INotifyChanged接口。但我不知道如何将这些数据与stackpanel容器绑定,这将允许我在后台自动切换到不同的堆栈面板视图。

    我想切换到的XAML示例是

    <GroupBox x:Class="Gui.CtrlCommSocketSettings"
        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:src="clr-namespace:Akribis.Gui"              
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        Header="Comm Settings"
        mc:Ignorable="d" 
        d:DesignHeight="80" d:DesignWidth="300">
    
    <Grid Height="70" VerticalAlignment="Top">
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="HorizontalAlignment" Value="Right"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="Margin" Value="0,0,3,0"/>
            </Style>
    
            <Style TargetType="TextBox">
                <Setter Property="Width" Value="120"/>
                <Setter Property="Margin" Value="0,1"/>
            </Style>
    
            <Style TargetType="CheckBox">
                <Setter Property="Margin" Value="0,4"/>
            </Style>
        </Grid.Resources>
    
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
    
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
    
        <TextBlock Grid.Row="0" Text="Server:" Name="MTextBlockServer"/>
        <TextBlock Grid.Row="1" Text="Port:"/>
    
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Server}" Name="MTextBoxServer"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Port}"/>
    </Grid>
    

    使用类似

    的cs文件
    namespace Gui
    {
        public partial class CtrlCommSocketSettings 
        {
            public CtrlCommSocketSettings()
            {
                InitializeComponent();
            }
        }
    }
    

    我不想以编程方式执行此操作,因为我知道我希望避免模型和视图之间的耦合。

    我不想做的例子,但此刻有: 在主XAML中,我有一个空的stackpanel

    <StackPanel Orientation="Vertical" Name="MCtrlCommSettings"></StackPanel> 
    

    我通过执行类似

    的操作明确地添加到此stackpanel
    MCtrlCommSettings.Children.Clear();
    MCtrlCommSettings.Children.Add(_serverCtrlCommSettings);
    

    我如何自动执行此操作?就像InotifyChanges将自动在视图和模型之间更新一样。欢迎任何建议。

    在线阅读,似乎我需要实现某种可观察的列表

1 个答案:

答案 0 :(得分:1)

我建议使用DataTemplates并为每种连接类型分离ViewModel。只需使用每个ViewModel的目标类型指定DataTemplates,然后使用ContentControl,使用主视图模型的内容属性绑定的CurrentConnection属性,这取决于ConnectionType组合框的SelectedValue。

<强>更新
源代码来说明解决方案:

XAML

<Window x:Class="MVVMExample.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:local="clr-namespace:MVVMExample"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="425">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Rs232ConnectionViewModel}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <TextBlock Grid.Row="0" Text="Rs232Port:" />

                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Rs232Port}" />
            </Grid>

        </DataTemplate>

        <DataTemplate DataType="{x:Type local:CanConnectionViewModel}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <TextBlock Grid.Row="0" Text="CanParam:" />

                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding CanParam}" />
            </Grid>
        </DataTemplate>

        <DataTemplate DataType="{x:Type local:EthernetConnectionViewModel}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <TextBlock Grid.Row="0" Text="Server:" />
                <TextBlock Grid.Row="1" Text="Port:"/>

                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding EthernetServer}" />
                <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding EthernetPort}"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <ComboBox x:Name="MCbConnect" SelectedValue="{Binding CurrentConnectionType}" ItemsSource="{Binding ConnectionTypes}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding ConnectionType}" />
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

        <ContentControl Grid.Row="1" Content="{Binding CurrentConnectionType}" />


    </Grid>
</Window>

C#

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

public class MainWindowViewModel : INotifyPropertyChanged
{
    ObservableCollection<ConnectionTypeViewModel> _connectionTypes;

    public ObservableCollection<ConnectionTypeViewModel> ConnectionTypes
    {
        get { return _connectionTypes; }
        private set { _connectionTypes = value; }
    }

    public MainWindowViewModel()
    {
        ConnectionTypes = new ObservableCollection<ConnectionTypeViewModel>(new ConnectionTypeViewModel[] 
        {
            new Rs232ConnectionViewModel() { ConnectionType = ConnectionType.Rs232, Rs232Port="COM1"},
            new CanConnectionViewModel() { ConnectionType = ConnectionType.Can},
            new EthernetConnectionViewModel() { ConnectionType = ConnectionType.Ethernet, EthernetServer="tcp://xxxx"},
        });

        CurrentConnectionType = ConnectionTypes[2];
    }

    private ConnectionTypeViewModel _currentConnectionType;
    public ConnectionTypeViewModel CurrentConnectionType
    {
        get { return _currentConnectionType; }
        set
        {
            _currentConnectionType = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentConnectionType)));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}


public class ConnectionTypeViewModel : INotifyPropertyChanged
{
    private ConnectionType _connectionTypeName;

    public ConnectionType ConnectionType
    {
        get { return _connectionTypeName; }
        set { _connectionTypeName = value; OnPropertyChanged(); }
    }

    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}


public class Rs232ConnectionViewModel : ConnectionTypeViewModel
{
    private string _rs232Port;

    public string Rs232Port
    {
        get { return _rs232Port; }
        set { _rs232Port = value; OnPropertyChanged(); }
    }
}


public class CanConnectionViewModel : ConnectionTypeViewModel
{
    private string _canParam;
    public string CanParam
    {
        get { return _canParam; }
        set { _canParam = value; OnPropertyChanged(); }
    }
}

public class EthernetConnectionViewModel : ConnectionTypeViewModel
{
    private string _ethernetServer;
    public string EthernetServer
    {
        get { return _ethernetServer; }
        set { _ethernetServer = value; OnPropertyChanged(); }
    }

    private string _ethernetPort;
    public string EthernetPort
    {
        get { return _ethernetPort; }
        set { _ethernetPort = value; OnPropertyChanged(); }
    }
}

public enum ConnectionType { Rs232 = 0, Can = 1, Ethernet = 2 };