C
C#7mo ago
Denis

WPF Custom controls/User controls binding issues and total confusion

need to create a reusable WPF control for displaying plugin settings. There is a defined set of settings, e.g., toggle, combo, file path. Each of those settings requires its own WPF control. My initial attempt was to create a User Control, and define a Dependency Property within it:
public static readonly DependencyProperty SelectedNodeProperty =
DependencyProperty.Register(
nameof(SelectedNode), // XAML attribute name
typeof(NodeViewModel), // Binding expected type
typeof(NodeSettings)); // Control name

public NodeViewModel SelectedNode
{
get => (NodeViewModel)GetValue(SelectedNodeProperty);
set => SetValue(SelectedNodeProperty, value);
}
public static readonly DependencyProperty SelectedNodeProperty =
DependencyProperty.Register(
nameof(SelectedNode), // XAML attribute name
typeof(NodeViewModel), // Binding expected type
typeof(NodeSettings)); // Control name

public NodeViewModel SelectedNode
{
get => (NodeViewModel)GetValue(SelectedNodeProperty);
set => SetValue(SelectedNodeProperty, value);
}
I set the data context in the constructor to this Initially, I've tried using IEnumerable as a type, but let's stay with this non-collection type for now. The view of the User control is:
<ItemsControl ItemsSource="{Binding SelectedNode.Settings, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<StackPanel Margin="0,5,0,5">
<TextBlock Text="Bobek" />
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type nodeSettings:ToggleSetting}">
<local:ToggleSettingView Setting="{Binding}" />
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
<ItemsControl ItemsSource="{Binding SelectedNode.Settings, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<StackPanel Margin="0,5,0,5">
<TextBlock Text="Bobek" />
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type nodeSettings:ToggleSetting}">
<local:ToggleSettingView Setting="{Binding}" />
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
I place my control into my MainWindow.xaml:
<controls:NodeSettings SelectedNode="{Binding SelectedNode, Mode=OneWay}" Grid.Column="1" />
<controls:NodeSettings SelectedNode="{Binding SelectedNode, Mode=OneWay}" Grid.Column="1" />
But the data is not bound!!!
1 Reply
Denis
Denis7mo ago
The MainWindow has its data context set to a ViewModel utilizing CommunityToolkit MVVM.
public sealed partial class MainWindowViewModel
: ObservableObject, IEditorViewModel
{
[ObservableProperty] private NodeViewModel? m_selectedNode;
...
}
public sealed partial class MainWindowViewModel
: ObservableObject, IEditorViewModel
{
[ObservableProperty] private NodeViewModel? m_selectedNode;
...
}
But here's the kicker... when I go back to the MainWindow.xaml, and modify the binding to:
<controls:NodeSettings SelectedNode="{Binding DataContext.SelectedNode, Mode=OneWay, ElementName=Root}" Grid.Column="1" />
<controls:NodeSettings SelectedNode="{Binding DataContext.SelectedNode, Mode=OneWay, ElementName=Root}" Grid.Column="1" />
where Root is the x:Name of the UserControl. What in the world is going on???