Рефакторинг XAML-разметки

186
19 мая 2017, 12:31

Читаю Роберта Мартина и пытаюсь постичь все тонкости рефакторинга.

Если с C#-кодом все более-менее понятно и код мало-помалу начинает радовать глаз, то с XAML всё печально. Разметка громоздкая и трудночитаемая. Понятно, что многое связано с xml-"наследственностью". Xml избыточен и не очень приятен для глаз, но всё же. Какие есть способы и кто что применяет для рефакторинга xaml?

В идеале хотелось бы избавиться от десятиуровневой иерархии и получить короткие "методы" по 5-7 строчек (как это у меня сделано в c#-коде).

Привожу разметку одного из окон моего последнего WPF-приложения (все 320 строчек "фарша"):

<Window x:Class="InfoReceiverB.Views.EditorWindow"
        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:InfoReceiverB.Views"
        mc:Ignorable="d"
        Title="Менеджер скриптов" Icon="/papers2.ico"
        WindowStartupLocation="CenterScreen"
        Height="700" Width="1100">
    <Grid Margin="3">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="2*"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="3*"/>
                </Grid.RowDefinitions>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <ListBox Padding="2.5" Margin="3"
                             ItemsSource="{Binding Repo.Queries}"
                             SelectedItem="{Binding SelectedQuery}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding Id}" Margin="0,0,2,0"/>
                                    <TextBlock Text="{Binding Caption}"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                    <StackPanel Grid.Column="1"
                                Margin="0,3,3,3">
                        <Button Content="+"
                                Padding="5" Margin="0,0,0,3"
                                Command="{Binding AddQueryCommand}"/>
                        <Button Content="-"
                                Padding="5" Margin="0,0,0,3"
                                Command="{Binding DelQueryCommand}"
                                CommandParameter="{Binding SelectedQuery}">
                            <Button.Style>
                                <Style TargetType="Button">
                                    <Style.Triggers>
                                        <Trigger Property="CommandParameter" Value="{x:Null}">
                                            <Setter Property="IsEnabled" Value="False"/>
                                        </Trigger>
                                    </Style.Triggers>
                                </Style>
                            </Button.Style>
                        </Button>
                    </StackPanel>
                </Grid>
                <GridSplitter Grid.Row="1" Height="3"
                              HorizontalAlignment="Stretch"
                              Background="DarkGray" Margin="3,0"/>
                <Grid Grid.Row="2" DataContext="{Binding SelectedQuery}">
                    <Grid.Style>
                        <Style TargetType="Grid">
                            <Style.Triggers>
                                <Trigger Property="DataContext" Value="{x:Null}">
                                    <Setter Property="IsEnabled" Value="False"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Grid.Style>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Id}"
                               Padding="5" Margin="3,3,0,3"/>
                    <TextBox Grid.Column="1"
                             Text="{Binding Caption}"
                             Padding="5" Margin="0,3,3,3"
                             AcceptsReturn="True"/>
                    <TextBox Grid.Row="1" Grid.ColumnSpan="2"
                             Text="{Binding Body}" 
                             FontFamily="Consolas" FontSize="14"
                             Padding="5" Margin="3,0,3,3"
                             AcceptsReturn="True" AcceptsTab="True"
                             HorizontalScrollBarVisibility="Auto"
                             VerticalScrollBarVisibility="Auto"/>
                </Grid>
            </Grid>
            <GridSplitter Grid.Column="1" Width="3"
                          HorizontalAlignment="Stretch"
                          Background="DarkGray" Margin="0,3"/>
            <Grid Grid.Column="2">
                <Grid.RowDefinitions>
                    <RowDefinition Height="2*"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="3*"/>
                </Grid.RowDefinitions>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <ListBox Padding="2.5" Margin="3"
                             ItemsSource="{Binding Repo.QueryPacks}"
                             SelectedItem="{Binding SelectedQueryPack}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding Id}" Margin="0,0,2,0"/>
                                    <TextBlock Text="{Binding Caption}"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                    <StackPanel Grid.Column="1"
                                Margin="0,3,3,3">
                        <Button Content="+"
                                Padding="5" Margin="0,0,0,3"
                                Command="{Binding AddQueryPackCommand}"/>
                        <Button Content="-"
                                Padding="5" Margin="0,0,0,3"
                                Command="{Binding DelQueryPackCommand}"
                                CommandParameter="{Binding SelectedQueryPack}">
                            <Button.Style>
                                <Style TargetType="Button">
                                    <Style.Triggers>
                                        <Trigger Property="CommandParameter" Value="{x:Null}">
                                            <Setter Property="IsEnabled" Value="False"/>
                                        </Trigger>
                                    </Style.Triggers>
                                </Style>
                            </Button.Style>
                        </Button>
                    </StackPanel>
                </Grid>
                <GridSplitter Grid.Row="1" Height="3"
                              HorizontalAlignment="Stretch"
                              Background="DarkGray" Margin="3,0"/>
                <Grid Grid.Row="2" DataContext="{Binding SelectedQueryPack}">
                    <Grid.Style>
                        <Style TargetType="Grid">
                            <Style.Triggers>
                                <Trigger Property="DataContext" Value="{x:Null}">
                                    <Setter Property="IsEnabled" Value="False"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Grid.Style>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Id}"
                                   Padding="5" Margin="3,3,0,3"/>
                        <TextBox Grid.Column="1"
                                 Text="{Binding Caption}"
                                 Padding="5" Margin="0,3,3,3"/>
                    </Grid>
                    <Grid Grid.Row="1">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <ListBox Name="list1" Padding="2.5" Margin="3"
                                 ItemsSource="{Binding DataContext.Repo.Queries,
                                                       RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding Id}" Margin="0,0,2,0"/>
                                        <TextBlock Text="{Binding Caption}"/>
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                        <StackPanel Grid.Column="1"
                                    Margin="0,3" VerticalAlignment="Center">
                            <Button Content="&gt;"
                                    Padding="5" Margin="0,0,0,3"
                                    Command="{Binding DataContext.AddQueryToPackCommand,
                                                      RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                                    CommandParameter="{Binding SelectedItem, ElementName=list1}">
                                <Button.Style>
                                    <Style TargetType="Button">
                                        <Style.Triggers>
                                            <Trigger Property="CommandParameter" Value="{x:Null}">
                                                <Setter Property="IsEnabled" Value="False"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                            </Button>
                            <Button Content="&lt;"
                                    Padding="5" Margin="0,7,0,3"
                                    Command="{Binding DataContext.DelQueryFromPackCommand,
                                                      RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                                    CommandParameter="{Binding SelectedItem, ElementName=list2}">
                                <Button.Style>
                                    <Style TargetType="Button">
                                        <Style.Triggers>
                                            <Trigger Property="CommandParameter" Value="{x:Null}">
                                                <Setter Property="IsEnabled" Value="False"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                            </Button>
                            <Button Content="^"
                                    Padding="5" Margin="0,0,0,3"
                                    Command="{Binding DataContext.UpQueryInPackCommand,
                                                      RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                                    CommandParameter="{Binding SelectedItem, ElementName=list2}">
                                <Button.Style>
                                    <Style TargetType="Button">
                                        <Style.Triggers>
                                            <Trigger Property="CommandParameter" Value="{x:Null}">
                                                <Setter Property="IsEnabled" Value="False"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                            </Button>
                            <Button Content="v"
                                    Padding="5" Margin="0,0,0,3"
                                    Command="{Binding DataContext.DownQueryInPackCommand,
                                                      RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                                    CommandParameter="{Binding SelectedItem, ElementName=list2}">
                                <Button.Style>
                                    <Style TargetType="Button">
                                        <Style.Triggers>
                                            <Trigger Property="CommandParameter" Value="{x:Null}">
                                                <Setter Property="IsEnabled" Value="False"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                            </Button>
                        </StackPanel>
                        <ListBox Grid.Column="2" Name="list2"
                                 Padding="2.5" Margin="3"
                                 ItemsSource="{Binding Queries}">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding Id}" Margin="0,0,2,0"/>
                                        <TextBlock Text="{Binding Caption}"/>
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </Grid>                    
                </Grid>
            </Grid>
        </Grid>
        <UniformGrid Grid.Row="1" HorizontalAlignment="Right"
                     Rows="1">
            <Button Grid.Column="1"
                    Content="Применить" IsDefault="True"
                    Padding="5" Margin="0,3,3,3"
                    Command="{Binding ApplyCommand}"
                    Click="ApplyButtonClick"/>
            <Button Grid.Column="2"
                    Content="Отмена" IsCancel="True"
                    Padding="5" Margin="0,3,3,3"/>
        </UniformGrid>
    </Grid>
</Window>

Буду рад любым рекомендациям и замечаниям, особенно с примерами

READ ALSO
Переопределение методов для массивов

Переопределение методов для массивов

Вопрос к любознательным гуру C#

209
Авторизация Googel API

Авторизация Googel API

Сейчас моё приложение использует для регистрацииjson файл

202
Считывание текстового файла

Считывание текстового файла

Возникла такая проблема: код запускается, но не считывает текстовый файл, тем более не создает новыйПодскажите как можно изменить

206
Как указать COLLATE для столбца таблицы?

Как указать COLLATE для столбца таблицы?

Имеется проект EF6 (code-First)В сущности File имеется свойство FullPath, содержащее полный путь к файлу в верхнем регистре

167