Я пытаюсь создать элемент управления или стиль, который позаботится о обычной ситуации «ярлык слева, элемент управления справа». Столбец меток должен иметь одинаковую ширину для всех меток.
Моя конечная цель - создать синтаксис, подобный следующему:
<l:LayoutGroup>
<TextBox l:LabelHelper.Label="111" />
<ComboBox l:LabelHelper.Label="Nice Box" ItemsSource="{Binding list}"/>
<ComboBox />
<Calendar l:LabelHelper.Label="Nice Calendar" HorizontalAlignment="Left"/>
<TextBox l:LabelHelper.Label="eyyoo"/>
</l:LayoutGroup>
На самом деле это получилось двумя разными способами. Но оба не предлагают поддержку времени разработки. Кратчайшая / лучшая настройка, которую я могу придумать, что действительно предлагает поддержку времени разработки, выглядит следующим образом:
<StackPanel Orientation="Vertical" Grid.IsSharedSizeScope="True">
<l:LayoutItem Title="cool textbox">
<TextBox />
</l:LayoutItem>
<l:LayoutItem Title="short">
<TextBox />
</l:LayoutItem>
<l:LayoutItem Title="ye">
<ComboBox />
</l:LayoutItem>
</StackPanel>
LayoutItem - это пользовательский контроль со следующим содержимым:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" SharedSizeGroup="Whatever"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Path=Title}"/>
<ContentPresenter Grid.Column="1" Content="{Binding Child"}/>
</Grid>
Так что, по сути, это просто набор сеток с ровно одним дочерним элементом и общей размерной группой.
Что я делаю, чтобы заставить мою целевую версию работать:
public static readonly DependencyProperty LabelProperty = DependencyProperty.RegisterAttached("Label",
typeof(string), typeof(LabelHelper), new UIPropertyMetadata("", Callback));
private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var child = d as Control;
var parent = LogicalTreeHelper.GetParent(child);
if (!(parent is StackPanel pnl))
return;
pnl.Children.Remove(child);
var wrapper = new LayoutItem
{
Title = GetLabel(child),
Child = child
};
pnl.Children.Add(wrapper);
}
public static string GetLabel(DependencyObject d) => (string)d.GetValue(LabelProperty);
public static void SetLabel(DependencyObject d, string value) => d.SetValue(LabelProperty, value);
Я беру любой элемент управления, к которому прикреплено свойство, удаляю его, оборачиваю в макет и вместо этого добавляю макет.
Работает, но поддержки времени разработки нет. И я понимаю, почему дизайнеру сложно это поддерживать. Я создаю другой элемент управления "во время выполнения", но на самом деле это не время выполнения, потому что я заметил, что этот метод "обратного вызова" обновляет представление времени разработки, если оно не слишком сложное ...
Есть ли способ заставить мой желаемый синтаксис работать? Я чувствую себя очень близко, но все подходы либо добавляют текстовый блок, сетку, что-нибудь к логическому дереву, чего на самом деле нет в xaml во время разработки. Кажется, это главная проблема, и я не знаю, решаемо ли это?
Я только что понял, что поддержка Desintime почти отсутствует. Это работает, когда я добавляю новый элемент управления с помощью LabelHelper. Это только не приспосабливается, если я изменяю самый длинный лейбл. Так что Callback срабатывает во время разработки, но что-то не так.