У меня есть DependecyProperty (с именем Block
) на пользовательском контроле XAML (с именем BlockPresenter
), который ожидает тип данных IBlock
.В этом IBlock
intefae есть метод Visual GetControl()
, помимо прочего, который возвращает некоторый элемент, позволяющий пользователю редактировать значения для этого конкретного блока.BlockPresenter
предоставляет способ выбора используемого блока (например, BlockA, BlockB и т. Д.), А также показывает возвращаемое значение GetControl
для самого блока.
Существуют модели, содержащие один или несколькоIBlock
свойства под разными именами.Каждая из этих моделей имеет свой собственный пользовательский элемент управления, который имеет модель DataContext.В XAML для элемента управления модели у меня есть строки, такие как <controls:BlockPresenter Block="{Binding Foo}" />
, чтобы показать элемент управления и позволить пользователю изменять тип блока или свойства для выбранного блока.
Когда пользователь меняет тип блока сВ раскрывающемся списке BlockPresenter создается новый экземпляр выбранного блока, который задается как свойство блока DependencyProperty, и презентатор вызывает для нового блока GetControl
.Это нормально, однако проблема в том, что это не отправляет новое значение в модель.
BlockPresenter.xaml
<Border BorderThickness="2" BorderBrush="#F00">
<StackPanel>
<ComboBox x:Name="BlockSelection" SelectedValuePath="BlockType" DisplayMemberPath="Name" SelectionChanged="BlockSelection_SelectionChanged" />
<ContentControl x:Name="ContentContainer" Margin="0" />
</StackPanel>
</Border>
BlockPresenter.xaml.cs
public BlockPresenter() {
InitializeComponent();
BlockSelection.ItemsSource = new List<BlockListItem> {
new BlockListItem("BlockA", typeof(BlockA)),
new BlockListItem("BlockB", typeof(BlockB)),
// BlockListItem is a simple class containing just "Name" and "BlockType" as read-only auto properties.
};
}
private static void OnBlockChange(DependencyObject conditionPresenter, DependencyPropertyChangedEventArgs eventArgs) {
var control = (BlockPresenter)conditionPresenter;
var newBlock = (IBlock)eventArgs.NewValue;
control.ContentContainer.Content = newBlock?.GetControl();
control.BlockSelection.SelectedValue = eventArgs.NewValue?.GetType();
}
public static readonly DependencyProperty BlockProperty = DependencyProperty.Register("Block", typeof(IBlock), typeof(BlockPresenter), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, OnBlockChange));
public IBlock Block {
get => (IBlock)GetValue(BlockProperty);
set => SetValue(BlockProperty, value);
}
private void BlockSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) {
Block = (IBlock)Activator.CreateInstance(BlockSelection.SelectedValue);
}
DefaultModelControl.xaml
<Grid>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefitions>
<Label Content="Main Block:" Grid.Row="0" />
<logic:BlockPresenter Block="{Binding MainBlock}" Grid.Row="0" Grid.Column="1" />
<Label Content="Subblock:" Grid.Row="1" />
<logic:BlockPresenter Block="{Binding SubBlock}" Grid.Row="1" Grid.Column="1" />
</Grid>
При изменении типов основного или вспомогательного блока для модели по умолчанию значение внутримодель (свойства MainBlock или SubBlock) не обновляются, чтобы отразить вновь выбранный блок.
Я знаю, что одним из решений может быть вызов пользовательского события (например, BlockChanged) из BlockPresenter, когда новое значениеустановить, передав это значение в качестве аргументов события, а затем записав это событие в файл DefaultModelControl.xaml.cs и установив для свойства новую ссылку.
Мне было интересно, есть ли другой способ сделать это без слушателейхотя, так как раздражает необходимость создавать их для каждого докладчика блока, который я хочу.
Я ошибаюсь?Хотелось бы услышать от людей конструктивные мысли по этому поводу.Спасибо:)