WPF:如何使用Style.Triggers

时间:2013-01-28 10:51:24

标签: wpf binding datatrigger

我想实现(文件)资源管理器,如图标显示。这些物品有日期和标签。

用户应该能够编辑标签:

  • 选择项目
  • 点击标签
  • Label的TextBlock替换为TextBox进行编辑

如何结束编辑(仅供参考):

  • 单击TextBox外的任何位置
  • 按Enter键盘键(通过实施ICommand?)

第一次我试图在代码中设置TextBlock和TextBox的可见性,发现这不是“正确”的方法。也许可以使用(数据)触发器编辑项目的标签?

我可以跟踪OnClickLabelBlock并设置selectedMedia.IsEditing = true;但它不会触发触发器。 知道为什么MediaItem.IsEditing属性值更改通知DataTrigger?它与执行顺序或优先级机制有关吗?

我会选择能够引导我选择“最佳”架构解决问题的答案。

感谢。

XAML:

<Window x:Class="WPFComponents.DailyImages"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Model="clr-namespace:WPFComponents.Model"
    Title="Media Items" Height="300" Width="300">

<ListView x:Name="_mediaItemList" ItemsSource="{Binding MediaItems}"
          ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionMode="Multiple">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="IsSelected" Value="{Binding IsSelected}" />
        </Style>
    </ListView.ItemContainerStyle>

    <ListView.ItemTemplate>
        <DataTemplate DataType="Model:MediaItem">

            <Grid Width="80" Margin="4">
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <Image HorizontalAlignment="Center" Stretch="Uniform" Source="{Binding Path=IconPath}" Width="70" />

                <StackPanel Grid.Row="2">
                    <TextBlock Text="{Binding Path=Date}" TextWrapping="Wrap" />

                    <TextBlock x:Name="_labelTextBlock" Text="{Binding Path=Label}" TextWrapping="Wrap"
                               PreviewMouseLeftButtonDown="OnClickLabelBlock">
                    </TextBlock>

                    <TextBox x:Name="_labelTextBox" Text="{Binding Path=Label}" Visibility="Collapsed"
                             TextWrapping="WrapWithOverflow" TextAlignment="Center">
                    </TextBox>
                </StackPanel>
            </Grid>

            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding IsEditing}" Value="True">
                    <Setter TargetName="_labelTextBlock" Property="Visibility" Value="Collapsed" />
                    <Setter TargetName="_labelTextBox" Property="Visibility" Value="Visible" />
                </DataTrigger>
            </DataTemplate.Triggers>

        </DataTemplate>
    </ListView.ItemTemplate>

    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel IsItemsHost="True" VerticalAlignment="Top" />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>

</ListView>

来源:

public partial class DailyImages
{
    public DailyImages()
    {
        InitializeComponent();

        ViewModel.DailyImages dailyImages = new ViewModel.DailyImages();
        // DailyImages has ObservableCollection<MediaItem> MediaItems property
        _mediaItemList.DataContext = dailyImages;
    }

    private void OnClickLabelBlock(object sender, MouseButtonEventArgs e)
    {
        TextBlock notes = sender as TextBlock;

        if (notes == null)
            return;

        MediaItem selectedMedia = notes.DataContext as MediaItem;

        if (selectedMedia == null)
        {
            // TODO: Throw exception
            return;
        }
        _mediaItemList.SelectedItems.Clear();
        selectedMedia.IsSelected = true;
        selectedMedia.IsEditing = true;
    }

public class MediaItem
{
    public MediaItem()
    {
        IsEditing = false;
        IsSelected = false;
    }

    public DateTime Date { get; set; }
    public string Label { get; set; }
    public string IconPath { get; set; }
    public bool IsEditing { get; set; }
    public bool IsSelected { get; set; }
}

参考文献: Dependency Property Value Precedence

第二部分:ListView & File Explorer Like Behaviour

2 个答案:

答案 0 :(得分:1)

MediaItem必须实现INotifyPropertyChanged并且必须绑定其每个属性,必须调用RaisePropertyChanged才能使绑定正常工作。在您的情况下,IsEditing上的Binding无法知道值已更改。

答案 1 :(得分:0)

要绑定您的IsEditing属性,必须在修改WPF时通知它。

然后你必须在INotifyPropertyChanged中实施MediaItem。 (或添加依赖项属性)

public class MediaItem : INotifyPropertyChanged
{
    public MediaItem()
    {
        IsEditing = false;
        IsSelected = false;
    }

    // Use the same pattern for Date, Label & IconPath if these value may change after the MediaItem instance has been added to the collection MediaItems.
    public DateTime Date { get; set; }
    public string Label { get; set; }
    public string IconPath { get; set; }

    private bool isSelected;
    public bool IsSelected
    {
        get { return isSelected; }
        set
        {
            if (isSelected != value)
            {
                isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }
    }

    private bool isEditing;
    public bool IsEditing
    {
        get { return isEditing; }
        set
        {
            if (isEditing != value)
            {
                isEditing = value;
                OnPropertyChanged("IsEditing");
            }
        }
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

否则,您的代码是正确的。