简体   繁体   中英

WPF data binding with ItemsControl and DataTrigger

I have a list of Foos and each have Name, ImageUrl and IsSelected properties. The images are shown within button and the one with IsSelected being true has red border around it. Hovering others show red border around that as well. That all works just fine.

But when I click another item, it changes the IsSelected value as true for that one (and false for the old one).

The ViewModel then says NotifyOfPropertyChange(() => Foos);

But nothing happens with the borders. I've tried to follow this example https://stackoverflow.com/a/19319456 with no avail. Below is my xaml code if you can spot the error.

<ItemsControl ItemsSource="{Binding Foos}" Grid.Column="0">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Tag="{Binding FooName}" Click="SelectFoo" Cursor="Hand">
                <Image Height="100" Width="100" Source="{Binding ImageUrl}"/>

                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Border BorderThickness="1" CornerRadius="3">
                            <ContentPresenter 
                                Margin="1"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                RecognizesAccessKey="True"/>

                            <Border.Style>
                                <Style TargetType="Border">
                                    <Setter Property="Background" Value="#292929"/>
                                    <Style.Triggers>
                                        <Trigger Property="IsMouseOver" Value="True">
                                            <Setter Property="BorderBrush" Value="Firebrick"/>
                                        </Trigger>
                                        <DataTrigger Binding="{Binding IsSelected}" Value="True">
                                            <Setter Property="BorderBrush" Value="Firebrick" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Border.Style>
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

I think that Your class Foo should implement INotifyPropertyChanged and invoke event ProprtyChanged when IsSelected property changes. For example:

public class Foo : INotifyPropertyChanged
{
    private string _fooName;
    private bool _isSelected;

    protected void OnNotifyPropertyChanged(string property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public string FooName { get => _fooName; set { _fooName = value; OnNotifyPropertyChanged(nameof(FooName)); } }
    public bool IsSelected { get => _isSelected; set { _isSelected = value; OnNotifyPropertyChanged(nameof(IsSelected)); } }
}

And then example implementation of list and Button click method:

public partial class MainWindow : Window
{
    public ObservableCollection<Foo> Foos { get; set; } 
        = new ObservableCollection<Foo>() { new Foo() { FooName = "A1" }, new Foo { FooName = "A2" }, new Foo() { FooName = "A3" } };
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (var foo in Foos)
            foo.IsSelected = false;
        foreach (var foo in Foos)
            if (foo.FooName == (sender as Button)?.Tag as string)
                foo.IsSelected = true;
    }
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM