Skip to content

Instantly share code, notes, and snippets.

@BYJRK
Created January 8, 2023 13:10
Show Gist options
  • Save BYJRK/37d6df1c9f1d198f73538c5167d50f6a to your computer and use it in GitHub Desktop.
Save BYJRK/37d6df1c9f1d198f73538c5167d50f6a to your computer and use it in GitHub Desktop.
SelectedItemBehavior
using Microsoft.Xaml.Behaviors;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfTutorials.RadioButtonBindings.Behaviors;
/// <summary>
/// Allows a <see cref="Panel"/> or <see cref="ItemsControl"/> to have a <see cref="ComboBox"/>-like behavior
/// that has a <see cref="SelectedItem"/> dependency property to be bound to a property in view model
/// </summary>
/// <example>
/// <code lang="xaml">
/// <![CDATA[
/// xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
/// xmlns:be="clr-namespace:WpfTutorials.RadioButtonBindings.Behaviors"
///
/// <StackPanel>
/// <i:Interaction.Behaviors>
/// <be:SelectedItemBehavior SelectedItem="{Binding SelectedItem}" />
/// </i:Interaction.Behaviors>
/// <RadioButton Tag="A" />
/// <RadioButton Tag="B" />
/// <RadioButton Tag="C" />
/// </StackPanel>
/// ]]>
/// </code>
/// </example>
public class SelectedItemBehavior : Behavior<FrameworkElement>
{
#region SelectedItem Dependency Property
public object SelectedItem
{
get => GetValue(SelectedItemProperty);
set => SetValue(SelectedItemProperty, value);
}
/// <summary>
/// The <see cref="SelectedItem"/> within this <see cref="Panel"/> or <see cref="ItemsControl"/>
/// </summary>
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
nameof(SelectedItem),
typeof(object),
typeof(SelectedItemBehavior),
new PropertyMetadata(null, OnSelectedItemChanged)
);
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = Interaction.GetBehaviors(d).OfType<SelectedItemBehavior>().FirstOrDefault();
if (behavior is null) return;
foreach (var child in behavior.Children)
{
child.IsChecked = child.Tag.Equals(e.NewValue);
}
}
#endregion
protected override void OnAttached()
{
AssociatedObject.Loaded += OnAssociatedLoaded;
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= OnAssociatedLoaded;
foreach (var child in Children)
{
child.Checked -= OnRadioButtonChecked;
}
}
private void OnAssociatedLoaded(object? sender, RoutedEventArgs e)
{
foreach (var child in Children)
{
child.Checked += OnRadioButtonChecked;
child.IsChecked = child.Tag.Equals(SelectedItem);
}
}
private void OnRadioButtonChecked(object sender, RoutedEventArgs e)
{
var radio = sender as RadioButton;
SelectedItem = radio!.Tag;
BindingOperations.GetBindingExpression(this, SelectedItemProperty).UpdateSource();
}
/// <summary>
/// Enumerate all <see cref="RadioButton"/> children of the <see cref="Behavior{T}.AssociatedObject"/>
/// </summary>
private IEnumerable<RadioButton> Children => AssociatedObject switch
{
Panel panel => panel.Children.OfType<RadioButton>(),
ItemsControl control => control.Items.OfType<RadioButton>(),
_ => Enumerable.Empty<RadioButton>(),
};
}
@LBCQ123
Copy link

LBCQ123 commented Sep 13, 2023

Interaction.GetBehaviors(d).OfType().FirstOrDefault(); 经常返回空

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment