WPF - 如何针对特定场景以正确的方式进行绑定?

WPF - how to do binding the right way for a particular scenario?

我是 WPF 的新手(从 WinForms 迁移过来)。我正在尝试将某些场景从 WinForms 应用程序转移到 WPF 应用程序:

  1. A window 有一个包含 3 列的 ListView 控件。
  2. 那里有一个按钮可以将新行添加到该 ListView。
  3. 第一列和第二列包含 ComboBox 控件。
  4. 第三列必须包含不同的控件,但一次只能显示一个控件。哪个是可见的,取决于第一列ComboBox的选择值。
  5. 每次用户从第一列的组合框中选择一个值时,第二列的组合框的内容都会改变。

一般情况是:用户从第一个ComboBox的类型列表中选择一个类型,然后第二个ComboBox将其内容更改为所选类型和第三列此时支持的操作列表必须更改其内容以显示支持该类型输入的控件。

我知道如何使用 WinForms 实现它,但我还不知道如何使用 WPF 实现它。有人可以帮助我实现它,或者任何人都可以提供有助于实现它的信息吗?

目前我有代码:

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        if (PropertyChanged != null) PropertyChanged(this, args);
    }
}

public class RecordFilter : ViewModelBase
{
    private static readonly ObservableCollection<KeyValuePair<PropertyInfo, string>> ColumnAliases =
        new ObservableCollection<KeyValuePair<PropertyInfo, string>>(Card.ColumnAliases);

    private KeyValuePair<PropertyInfo, string> _currentSelectedProperty;

    public IEnumerable<OperationInfo> Operations
    {
        get
        {
            return Operations.GetOperationInfosForType(GetTypeUnwrapNullable(SelectedProperty.Key.PropertyType));
        }
    }

    public OperationInfo SelectedOperation { get; set; }

    public KeyValuePair<PropertyInfo, string> SelectedProperty
    {
        get { return _currentSelectedProperty; }
        set
        {
            _currentSelectedProperty = value;

            OnPropertyChanged("Operations");
        }
    }

    public ObservableCollection<KeyValuePair<PropertyInfo, string>> Properties
    {
        get { return ColumnAliases; }
    }

    //DateTime or int or float, depends on the selected property type
    //public object PropertyValue { get; set; }
}

这是 XAML 代码:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Converters="clr-namespace:App.Converters" x:Class="App.DialogWindows.CardFilterWindow"
        Title="Search filters" Height="347" Width="628" x:Name="wdw" ShowInTaskbar="False" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <Converters:NotNullObjectToEnabledConverter x:Key="NotNullObjectToEnabledConverter"/>
    </Window.Resources>
    <DockPanel>
        <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Center" Height="Auto">
            <Button x:Name="bnOK" Margin="5" Width="41" Content="OK" IsDefault="True" Click="bnOK_Click"/>
            <Button x:Name="bnCancel" Margin="5" Content="Отмена" IsCancel="True"/>
        </StackPanel>
        <ListView ItemsSource="{Binding Filters, ElementName=wdw}" Name="LvExpr" DataContext="{Binding Filters, ElementName=wdw}">
            <ListView.Resources>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                </Style>
            </ListView.Resources>
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Alias" Width="210">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox VerticalAlignment="Center"
                                    ItemsSource="{Binding Properties}"
                                    DisplayMemberPath="Value"
                                    SelectedValue="{Binding SelectedProperty, Mode=TwoWay}"
                                    />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Operation" Width="150">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox VerticalAlignment="Center"
                                    ItemsSource="{Binding Operations}"
                                    DisplayMemberPath="OperationAlias"
                                    SelectedValue="{Binding SelectedOperation, Mode=TwoWay}"
                                />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Value" Width="100">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Text="ValidatesOnDataErrors=True}" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Width="33">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Button Tag="{Binding Mode=OneWay}" Click="BnDelete_Click" ToolTip="Delete filter">
                                    <Image Source="delete.ico" Height="16" Width="16"/>
                                </Button>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                        <GridViewColumnHeader>
                            <DataGridCell>
                                <Button Click="ButtonAdd_Click" Height="22" Padding="0" ToolTip="Add filter">
                                    <Image Source="plus.ico" Focusable="False"/>
                                </Button>
                            </DataGridCell>
                        </GridViewColumnHeader>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </DockPanel>
</Window>

在您的视图模型中,设置列表属性,并在所选值更改时(通过 INotifyPropertyChanged.PropertyChanged 事件)相应地过滤掉它们。

有关综合示例,请参阅 this post。它使用一种称为 MVVM 的技术,该技术广泛用于 WPF 并代表 ModelViewViewModel。我强烈建议您学习这项技术并将其用于您的 XAML 相关项目。 Here 是网上众多教程中的一个快速入门教程。