I have a viewmodel with multiple counters which are used in serval methods. In the view model there is also a collection of class MenuItem which holds information the create the dynamic menuitems in the ribbon. On some of those menuitems i want to display the counter through a badge.
But to do this i need the bind the badge to the counter property. In my menuitem class i have the path for the binding, but how can i thell my menuitem template to bind to the path it has in it's own binding.
Examples are simplified
public class ViewmodelSample
{
public int counter1 { get; set; }
public ICollection<MenuItem> MenuItems { get; set; } = new ObservableCollection<MenuItem>();
public void Sample()
{
MenuItems.Add(new MenuItem()
{
Name = "Test button",
CounterPath = "counter1"
});
}
public class MenuItem
{
public string Name { get; set; }
public string CounterPath { get; set; }
}
}
<ItemsControl ItemsSource="{Binding Path=MenuItems}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Path={Binding CounterPAth}}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You cannot bind the Path
property in the Binding
markup extension, it is not a DependencyProperty
.
You could identify the target counter with eg a Counter
property of type int
. Apply a Style
to your TextBlock
with triggers that provide the bindings to the corresponding counter properties on the ViewmodelSample
. You need a RelativeSource
binding as the counters are in the parent DataContext
.
<Style x:Name="CounterTextBlockStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Counter}" Value="1">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.counter1}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Counter}" Value="2">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.counter2}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Counter}" Value="3">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.counter3}"/>
</DataTrigger>
</Style.Triggers>
</Style>
For now i have created a helper class. Maybe is not perfect but this works for me (for now).
Helper class
public class DynamicBindingHelper
{
public string PropertyNaam { get; set; }
public static string GetPath(DependencyObject obj)
{
return (string)obj.GetValue(PathProperty);
}
public static void SetPath(DependencyObject obj, string value)
{
obj.SetValue(PathProperty, value);
}
public static readonly DependencyProperty PathProperty =
DependencyProperty.RegisterAttached("Path", typeof(string), typeof(DynamicBindingHelper), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnPathChanged)));
private static void OnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null || (e.NewValue is string val && val.IsNullOrWhiteSpace()))
return;
if (d == null)
return;
var binding = new Binding($"DataContext.{e.NewValue}")
{
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(UserControl), 1),
Mode=BindingMode.OneWay
};
switch (d)
{
case TextBlock _:
BindingOperations.ClearBinding(d, TextBlock.TextProperty);
BindingOperations.SetBinding(d, TextBlock.TextProperty, binding);
break;
case Badge _:
BindingOperations.ClearBinding(d, Badge.ContentProperty);
BindingOperations.SetBinding(d, Badge.ContentProperty, binding);
break;
}
}
}
WPF usage
<dx:Badge helper:DynamicBindingHelper.Path="{Binding TellerNaam}" Padding="2,2,2,3" FontSize="10" Margin="-3,5,3,-5" />
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.