2
\$\begingroup\$

I have control with RadioButtons. Each RadioButton represent some state of document. Each document have a lot of labels, buttons and another trash. I need to collapse different labels, buttons, other... In different states. I think that I am building big crutch. What is the better way to implement this functionality?

XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1.Converters"
        xmlns:enums="clr-namespace:WpfApplication1.Enums"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:MultiBooleanToVisibilityConverter x:Key="Converter" />
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Vertical">
            <RadioButton Content="First" x:Name="First"></RadioButton>
            <RadioButton Content="Second" x:Name="Second"></RadioButton>
            <RadioButton Content="Third" x:Name="Third"/>
            <RadioButton Content="Fourth" x:Name="Fourth"></RadioButton>
        </StackPanel>
        <StackPanel Orientation="Vertical" Grid.Row="1">
            <Label Content="Test1">
                <Label.Visibility>
                    <MultiBinding Converter="{StaticResource Converter}">
                        <MultiBinding.ConverterParameter>
                            <x:Array Type="{x:Type sys:Enum}">
                                <enums:DocumentTypes>Second</enums:DocumentTypes>
                                <enums:DocumentTypes>Fourth</enums:DocumentTypes>
                            </x:Array>
                        </MultiBinding.ConverterParameter>
                        <Binding ElementName="First" Path="IsChecked" />
                        <Binding ElementName="Second" Path="IsChecked" />
                        <Binding ElementName="Third" Path="IsChecked" />
                        <Binding ElementName="Fourth" Path="IsChecked" />
                    </MultiBinding>
                </Label.Visibility>
            </Label>
            <Label Content="Test2">
                <Label.Visibility>
                    <MultiBinding Converter="{StaticResource Converter}">
                        <MultiBinding.ConverterParameter>
                            <x:Array Type="{x:Type sys:Enum}">
                                <enums:DocumentTypes>First</enums:DocumentTypes>
                                <enums:DocumentTypes>Third</enums:DocumentTypes>
                            </x:Array>
                        </MultiBinding.ConverterParameter>
                        <Binding ElementName="First" Path="IsChecked" />
                        <Binding ElementName="Second" Path="IsChecked" />
                        <Binding ElementName="Third" Path="IsChecked" />
                        <Binding ElementName="Fourth" Path="IsChecked" />
                    </MultiBinding>
                </Label.Visibility>
            </Label>
            <Label Content="Test3">
                <Label.Visibility>
                    <MultiBinding Converter="{StaticResource Converter}">
                        <MultiBinding.ConverterParameter>
                            <x:Array Type="{x:Type sys:Enum}">
                                <enums:DocumentTypes>Fourth</enums:DocumentTypes>
                                <enums:DocumentTypes>First</enums:DocumentTypes>
                            </x:Array>
                        </MultiBinding.ConverterParameter>
                        <Binding ElementName="First" Path="IsChecked" />
                        <Binding ElementName="Second" Path="IsChecked" />
                        <Binding ElementName="Third" Path="IsChecked" />
                        <Binding ElementName="Fourth" Path="IsChecked" />
                    </MultiBinding>
                </Label.Visibility>
            </Label>
        </StackPanel>
    </Grid>
</Window>

ENUM

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApplication1.Enums
{
    public enum DocumentTypes
    {
        First, Second, Third, Fourth
    }
}

CONVERTER

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using WpfApplication1.Enums;

namespace WpfApplication1.Converters
{
    class MultiBooleanToVisibilityConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Dictionary<string, bool> dict = new Dictionary<string, bool>();
            dict.Add("First", (bool)values[0]);
            dict.Add("Second", (bool)values[1]);
            dict.Add("Third", (bool)values[2]);
            dict.Add("Fourth", (bool)values[3]);
            if (parameter != null)
            {
                List<DocumentTypes> result = ((IEnumerable)parameter).Cast<DocumentTypes>().ToList();
                foreach (DocumentTypes type in result)
                {
                    if (dict[type.ToString()])
                    {
                        return System.Windows.Visibility.Visible;
                    }
                }
            }
            return System.Windows.Visibility.Collapsed;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ I think you should use styles with triggers - unfortunatelly I cannot show you how, I'm not that good in WPF. \$\endgroup\$ – t3chb0t Oct 5 '16 at 15:02
  • \$\begingroup\$ For one don't like the tight couple to enum value. \$\endgroup\$ – paparazzo Oct 5 '16 at 19:19
4
\$\begingroup\$

OPTION A

As proposed by @t3chb0t, you could realize it as XAML-only solution with triggers:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Vertical">
        <RadioButton Content="First" x:Name="First"></RadioButton>
        <RadioButton Content="Second" x:Name="Second"></RadioButton>
        <RadioButton Content="Third" x:Name="Third"/>
        <RadioButton Content="Fourth" x:Name="Fourth"></RadioButton>
    </StackPanel>
    <StackPanel Orientation="Vertical" Grid.Row="1">
        <Label Content="Test1">
            <Label.Style>
                <Style TargetType="Label">
                    <Setter Property="Visibility" Value="Collapsed" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=First}" Value="True">
                            <Setter Property="Visibility" Value="Visible" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=Fourth}" Value="True">
                            <Setter Property="Visibility" Value="Visible" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Label.Style>
        </Label>
        <Label Content="Test2">
            <Label.Style>
                <Style TargetType="Label">
                    <Setter Property="Visibility" Value="Collapsed" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=First}" Value="True">
                            <Setter Property="Visibility" Value="Visible" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=Third}" Value="True">
                            <Setter Property="Visibility" Value="Visible" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Label.Style>
        </Label>
        <Label Content="Test3">
            <Label.Style>
                <Style TargetType="Label">
                    <Setter Property="Visibility" Value="Collapsed" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=Fourth}" Value="True">
                            <Setter Property="Visibility" Value="Visible" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=First}" Value="True">
                            <Setter Property="Visibility" Value="Visible" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Label.Style>
        </Label>
    </StackPanel>
</Grid>

The downside is, that the logic is blurred in XAML and therefore difficult to read and extended.

OPTION B

A second option is to use a view model (let it call MainViewModel) and data binding:

  • Create an enum with one value for each of the radio buttons
  • Bind the selected value of the radio buttons to a property of the view model
  • Create on view model for the labels (let it call LabelViewModel).
  • Give the MainViewModel a list of LabelViewModels and bind them to an ItemsControl with a Label as DataTemplate
  • Update the LabelViewModels within the MainViewModel if the selected value of the radio buttons changed.

That approach is better to understand and extend IMHO.

\$\endgroup\$
  • \$\begingroup\$ This is exactly what I meant ;-D as to The downside is, that the logic is blurred in XAML I think you can move the logic (the triggers) into a resource dictionary and make it appliable to any control with that style not just in this xaml file. \$\endgroup\$ – t3chb0t Oct 6 '16 at 15:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.