C#相对于MainWindow设置translatetransform X和Y属性

我在ItemsControl中托管了一个Wrappanel,它包含在一个scrollviewer中。 wrappanel中的项目填充了绑定。 每个项目都有一个带数据触发器的datatemplate。 该触发器用于将项目设置为屏幕中心的动画。 我试图用translatetransform做到这一点,但问题是translatetransform的X和Y属性是相对于项目本身而不是主机容器,因此每个项目都有不同的动画。 如下所示:

webm 1 webm 2

项目模板XAML:

              

我试着像这样使用UIElement.TranslatePoint:

整个UserControl,一切都是:

                                                 

DataContext ViewModel:

 public class CountryViewModel : BaseViewModel { private ObservableCollection countries; private DelegateCommand loadDataCommand; public CountryViewModel ( ) { ViewModelFinder.Add(this); } public ObservableCollection Countries { get { return countries; } set { this.countries = value; this.NotifyPropertyChanged(); } } public DelegateCommand LoadDataCommand { get { if ( this.loadDataCommand == null ) this.loadDataCommand = new DelegateCommand(async icMain => await LoadDataMethod(icMain)); return this.loadDataCommand; } } private async Task LoadDataMethod (ItemsControl icMain) { if ( this.Countries == null ) { var countries = await CountryService.Instance.GetAllAsync(); this.Countries = new ObservableCollection(); var util = new Util(); foreach ( var country in countries.Take(40) ) { var countryItem = new CountryItem { Name = country.Name, Iso2 = country.Iso2, IsoAlpha3 = country.IsoAlpha3, IsoUnM49Numerical = country.IsoUnM49Numerical, Id = country.Id }; var imageBytes = await util.GetImageBytesAsync(country.CountryFlagUrl); countryItem.ImageUrl = country.CountryFlagUrl; this.Countries.Add(countryItem); countryItem.This = icMain.ItemContainerGenerator.ContainerFromItem(countryItem) as UIElement; } } } } 

表示wrappanel中项目的类:

 public class CountryItem : ObservableObject { private bool isEnabled = true; private bool isInEditMode; private bool isVisible = true; private DelegateCommand isInEditModeToggleCommand; private string name; private string iso2; private string isoAlpha3; private int isoUnM49Numerical; private string imageUrl; private Guid id; private UIElement @this; public CountryItem ( ) { } public bool IsEnabled { get { return isEnabled; } set { this.isEnabled = value; this.NotifyPropertyChanged(); } } [Required(AllowEmptyStrings = false, ErrorMessage = "Name is required.")] public string Name { get { return this.name; } set { this.name = value; this.NotifyPropertyChanged(); } } [Required(AllowEmptyStrings = false, ErrorMessage = "Iso2 is required.")] public string Iso2 { get { return this.iso2; } set { this.iso2 = value; this.NotifyPropertyChanged(); } } [Required(AllowEmptyStrings = false, ErrorMessage = "Iso Alpha3 is required.")] public string IsoAlpha3 { get { return this.isoAlpha3; } set { this.isoAlpha3 = value; this.NotifyPropertyChanged(); } } [Required(AllowEmptyStrings = false, ErrorMessage = "Iso Un M49 Numerical is required.")] public int IsoUnM49Numerical { get { return this.isoUnM49Numerical; } set { this.isoUnM49Numerical = value; this.NotifyPropertyChanged(); } } public string ImageUrl { get { return imageUrl; } set { this.imageUrl = value; this.NotifyPropertyChanged(); } } public Guid Id { get { return id; } set { this.id = value; } } public bool IsInEditMode { get { return isInEditMode; } set { this.isInEditMode = value; this.NotifyPropertyChanged(); } } public DelegateCommand IsInEditModeToggleCommand { get { if ( this.isInEditModeToggleCommand == null ) this.isInEditModeToggleCommand = new DelegateCommand(IsInEditModeToggleMethod); return this.isInEditModeToggleCommand; } } public bool IsVisible { get { return isVisible; } set { this.isVisible = value; this.NotifyPropertyChanged(); } } public UIElement This { get { return this.@this; } set { this.@this = value; this.NotifyPropertyChanged(); } } private void IsInEditModeToggleMethod ( ) { var countryViewModel = ViewModelFinder.FindOne(); countryViewModel.Countries.Where(x=>x.Id != this.Id).ToList().ForEach(ci => ci.IsVisible = false); this.This.TranslatePoint(new Point(400, 500), Application.Current.MainWindow) this.IsInEditMode = !this.IsInEditMode; } } 

您可以使用UIElement.TranslatePoint函数转换坐标。 那么你只需要一种方法来使用动画中的翻译值,应该有多种方法来实现这一点。

一种选择是,在集合外部具有专用的CurrentEditItem ,并基于是否设置此属性来修改窗口内容模板。 这样,窗口和项目之间的关系应该更容易建模。 但我确信它也可以在To值上抛出绑定和转换器,以便让它们转换窗口到项目的坐标值。

例如,在窗口上实例化为静态资源的ConverterParameter带有对窗口的引用)和带有项目的ConverterParameter允许您转换窗口和项目坐标之间的任何incomming值。

解决方案是从xaml中删除故事板动画并在项目对象中以编程方式执行。 当我创建这些项来填充包装面板时,我添加了对创建的ContentPresenter的引用,该引用表示项本身和根父,在这种情况下是UserControl。

需要引用的ContentPresenter来为项目设置动画。 需要引用的根父UserControl来获取用户控件中项的当前位置。

现在动画看起来像这样:

webm 3 webm 4

我在CountryItem中添加了这个方法:

  private void AnimateToCenter ( ) { var sbTranslate = new Storyboard(); var daTranslateX = new DoubleAnimation(); var daTranslateY = new DoubleAnimation(); var duration = new Duration(TimeSpan.FromSeconds(2)); daTranslateX.Duration = duration; daTranslateY.Duration = duration; sbTranslate.Duration = duration; var exponentialEase = new ExponentialEase(); exponentialEase.EasingMode = EasingMode.EaseInOut; exponentialEase.Exponent = 16; daTranslateX.EasingFunction = exponentialEase; daTranslateY.EasingFunction = exponentialEase; sbTranslate.Children.Add(daTranslateX); sbTranslate.Children.Add(daTranslateY); Storyboard.SetTarget(daTranslateX, this.This); Storyboard.SetTarget(daTranslateY, this.This); this.This.RenderTransform = new TranslateTransform(); Storyboard.SetTargetProperty(daTranslateX, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)")); Storyboard.SetTargetProperty(daTranslateY, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)")); //get the current point of the selected item var currentPoint = this.This.TranslatePoint(new Point(), this.Parent); //get actual width and height of the parent so we can calculate to which position to calculate var parentWidth = (this.Parent as UserControl).ActualWidth; var parentHeight = (this.Parent as UserControl).ActualHeight; //get actual width and height of the item itself to center the item correctly //this is needed because the X and Y coordinates of the item are top and left var thisWidth = (this.This as ContentPresenter).ActualWidth; var thisHeight = (this.This as ContentPresenter).ActualHeight; //animate the item to the center of the screen daTranslateX.To = (parentWidth / 2) - currentPoint.X - (thisWidth / 2); daTranslateY.To = (parentHeight / 2) - currentPoint.Y - (thisHeight / 2); sbTranslate.Begin(); } 

它在这里被称为:

  private void IsInEditModeToggleMethod ( ) { this.IsEllipseVisible = true; var countryViewModel = ViewModelFinder.FindOne(); countryViewModel.Countries.Where(x=>x.Id != this.Id).ToList().ForEach(ci => ci.IsVisible = false); this.IsInEditMode = !this.IsInEditMode; this.AnimateToCenter(); }