开发者

How can I change the property of an Element based on the property of an INotifyPropertyChanged object in an ObservableCollection?

I've got an ObservableCollection<User> full of User objects which implement INotifyPropertyChanged. The collection is set as the DataContext of my Window, which contains a ListBox (whose ItemsSource is also set to the same collection), a number of TextBoxes, and a save Button, standard CRUD setup.

I want to change the background of the save Button (and the background of the row in the ListBox which corresponds to the "current item") if one of the properties of the User objects changes. Should I be looking at styles and triggers?

I have the following Style applied to my save Button, and the User objects have a public bool IsDirty property.

<Style x:Key="PropertyChangedStyle" TargetType="Button">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Source=???, Path=IsDirty}" Value="True">
            <Setter Property="Background" Value="Red" />
        </DataTrigger>
    </Style.Triggers>
</Style>

<Button ... Style="{StaticResource PropertyChangedStyle}">

I think I'm on the right track, but I don't understand how to point the binding to "the current item in an observable list which is set as the datacontext", where "current item" in this case is described by CollectionViewSource.GetDefaultView(ListOfUsers).CurrentItem (where ListOfUsers is my ObservableCollection<User>开发者_运维技巧).


The DataContext of each of the items in your ListBox will be automatically bound to your User instances, so it is not necessary to set the source in your binding. You can bind directly from the style of your ListBoxItems to properties on your User instances.

You can achieve it like this:

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="ASD_Answer011.MainWindow"
        x:Name="Window"
        Title="MainWindow"
        Width="640" Height="480">
        <Window.Resources>
            <DataTemplate x:Key="ItemTemplate">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Property1}"/>
                    <CheckBox IsChecked="{Binding Property2}"/>
                </StackPanel>
            </DataTemplate>
            <Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=IsDirty}" Value="True">
                        <Setter Property="Background" Value="Red" />
                    </DataTrigger>
                </Style.Triggers>
                <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                <Setter Property="Padding" Value="2,0,0,0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                                <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsSelected" Value="true">
                                    <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                                </Trigger>
                                <MultiTrigger>
                                    <MultiTrigger.Conditions>
                                        <Condition Property="IsSelected" Value="true"/>
                                        <Condition Property="Selector.IsSelectionActive" Value="false"/>
                                    </MultiTrigger.Conditions>
                                    <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                                </MultiTrigger>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Resources>

        <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
            <ListBox ItemTemplate="{DynamicResource ItemTemplate}" ItemsSource="{Binding Collection}" ItemContainerStyle="{DynamicResource ListBoxItemStyle1}"/>
        </Grid>
    </Window>

This is how it looks when the application is running:

How can I change the property of an Element based on the property of an INotifyPropertyChanged object in an ObservableCollection?


WPF supports the idea of a "current item" in a collection, and will track the current item for you. You can write a binding path that refers to a collection's current item.

See the "Current Item Pointers" section on the Data Binding Overview page on MSDN.

I'm thinking that, if your ListBox's ItemsSource is bound to (for example) {Binding ListOfUsers}, then your button could use {Binding ListOfUsers/IsDirty}.

I haven't used this much, but I think you may have to set your ListBox's IsSynchronizedWithCurrentItem property to True to make this work.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜