开发者

Style Listviews Selector.SelectedItem

I have ListView with SelectionMode=extended and style for ListViewItem thus:

MainWindow.xaml:

<Window x:Class="ListViewSelection.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="{x:Type ListViewItem}">
            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Aqua"/>
            </Style.Resources>
            <!--<Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="Aqua" />
                </Trigger>
            </Style.Triggers>-->
        </Style>
    </Window.Resources>
    <StackPanel>
        <ListView Name="MyListView" ItemsSource="{Binding MyList}" SelectionChanged="SelectionChanged" SelectionMode="Extended" />
        <Label Name="MyLabel" />
    </StackPanel>
</Window>

MainWindow.xaml.cs:

using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;

namespace ListViewSelection
{
    public partial class MainWindow : Window
    {

        public ObservableCollection<string> MyList { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            MyList = new ObservableCollection<string>();
            MyList.Add("Jane");
            MyList.Add("Paul");
            MyList.Add("Sally");
            MyList.Add("Ian");
        }

        private void SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            MyLabel.Content = (sender as ListBox).SelectedItem;
        }
    }
}

This sets the color fine for all selected item开发者_如何学Pythons. But I need to also style the Selector.SelectedItem, which is the 'active' or first item in the selection. This is the one that the label displays.

Any help? Thanks!


You could expose IsFirstInSelection property in your ViewData class (I suppose you have it).

Then you could place DataTrigger for monitoring changes like this:

        <Style.Triggers>
            <DataTrigger Binding="{Binding IsFirstInSelection}">
                <Setter Property="Background"
                        Value="Blue"/>
            </DataTrigger>
        </Style.Triggers>

Also in your case I'd recommend to avoid changing HighlightBrushKey, but achieve your goal via changing Background property. You could also expose IsSelected property in ViewData class, so it looks this:

public class ViewData: ObservableObject
{
    private bool _isSelected;
    public bool IsSelected
    {
        get
        {
            return this._isSelected;
        }
        set
        {
            if (this._isSelected != value)
            {
                this._isSelected = value;
                this.OnPropertyChanged("IsSelected");
            }
        }
    }

    private bool _isFirstInSelection;
    public bool IsFirstInSelection
    {
        get
        {
            return this._isFirstInSelection;
        }
        set
        {
            if (this._isFirstInSelection != value)
            {
                this._isFirstInSelection = value;
                this.OnPropertyChanged("IsFirstInSelection");
            }
        }
    }
}

And your style sets Background based on both properties:

        <Style x:Key="TreeItemStyle"
               TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected"
                    Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
            <Setter Property="IsFirstInSelection"
                    Value="{Binding Path=IsFirstInSelection}"/>
            <Setter Property="Background"
                    Value="Green"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsSelected}"
                             Value="True">
                    <Setter Property="Background" 
                            Value="Red"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsFirstInSelection}">
                    <Setter Property="Background"
                        Value="Blue"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

Of course in model or in view code behind you should monitor IsSelected property changed notifications and set/reset IsFirstInSelection according to selected items.

I hope you understand my idea.

------- EDITED --------

At first I continue to insist that you should develop proper ViewData class:

public class ViewData : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        var ev = this.PropertyChanged;
        if (ev != null)
        {
            ev(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public ViewData(string name)
    {
        this._personName = name;
    }

    private string _personName;
    public string PersonName
    {
        get
        {
            return this._personName;
        }
        set
        {
            if (this._personName != value)
            {
                this._personName = value;
                this.OnPropertyChanged("PersonName");
            }
        }
    }

    private bool _isFirstSelected;
    public bool IsFirstSelected
    {
        get
        {
            return this._isFirstSelected;
        }
        set
        {
            if (this._isFirstSelected != value)
            {
                this._isFirstSelected = value;
                this.OnPropertyChanged("IsFirstSelected");
            }
        }
    }
}

During handling SelectionChanged event you should modify property IsFirstSelected like this:

public ObservableCollection<ViewData> MyList { get; set; }
private void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var lb = sender as ListBox;
    if (lb != null)
    {
        MyLabel.Content = lb.SelectedItem;
        foreach (var item in this.MyList)
        {
            if (item == lb.SelectedItem)
            {
                item.IsFirstSelected = true;
            }
            else
            {
                item.IsFirstSelected = false;
            }
        }
    }
}

But default ListViewItem template doesn't react on Background setters so you should override its template in style:

<Style TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListViewItem">
                <Grid Background="{TemplateBinding Background}">
                    <ContentPresenter Content="{Binding PersonName}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected"
                                Value="True">
                        <Setter Property="Background"
                                Value="Yellow"/>
                    </Trigger>

                    <DataTrigger Binding="{Binding IsFirstSelected}" 
                                    Value="True">
                        <Setter Property="Background" 
                                Value="Aqua" />
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style> 

If this solution isn't acceptable, please tell me. I've some ideas but have no enough time to check them in code right now.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜