Arlen Keshabyan
Arlen Keshabyan

Reputation: 107

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

I'm pretty new to WPF (moving from WinForms). I'm trying to transfer some scenario from a WinForms application to a WPF one:

  1. A window has a ListView control with 3 columns.
  2. There is a button there to add new rows to that ListView.
  3. The first and the second columns contain the ComboBox control.
  4. The third column must contain different controls but just one at a time is visible. Which one is visible, it depends on the selected value of the ComboBox at the first column.
  5. The content of the ComboBox at the second column changes every time a user selects a value from the ComboBox at the first column.

The general scenario is: a user selects a type from the list of types from the first ComboBox, after that the second ComboBox changes its content to a list of supported operations for the selected type and the third column at that time must change its content to display a control that supports the input for that type.

I know how to implement it using WinForms but I have no idea yet how to do it using WPF. Can someone help me to implement it or can anyone help with the information that facilitate implementing that?

I have the code so far:

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; }
}

Here is the XAML code:

<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>

Upvotes: 1

Views: 85

Answers (1)

Shimmy Weitzhandler
Shimmy Weitzhandler

Reputation: 104692

In your view-model, set up the list properties, and filter them out accordingly when the selected value changes (via the INotifyPropertyChanged.PropertyChanged event).

See this post for a comprehensive example. It uses a technique called MVVM that is used extensively with WPF and stands for ModelViewViewModel. I highly recommend you to learn this technique and utilize it in your XAML-related projects. Here is one quick start tutorial, out of the many on the net.

Upvotes: 1

Related Questions