Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a MosaicControl to repeat an image #702

Merged
merged 11 commits into from
Jan 5, 2017

Conversation

samoteph
Copy link
Contributor

@samoteph samoteph commented Dec 8, 2016

As asked in the issue #658, I propose MosaicControl.
It works with XAML or Composition (Composition is the default).
You can animate the image or synchronize it with a ScrollViewer to create a parallax effect.

@dnfclas
Copy link

dnfclas commented Dec 8, 2016

Hi @samoteph, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla2.dotnetfoundation.org.

TTYL, DNFBOT;

@dnfclas
Copy link

dnfclas commented Dec 8, 2016

@samoteph, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

@@ -1,6 +1,7 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0",
"Robmikh.CompositionSurfaceFactory": "0.7.0-alpha",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mind updating the nuspec in /build folder?

Copy link
Contributor Author

@samoteph samoteph Dec 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry but I don't understand what must i do.
Could you give me some hint ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done !

@@ -193,6 +198,7 @@
<ItemGroup>
<EmbeddedResource Include="Properties\Microsoft.Windows.Toolkit.UI.Controls.rd.xml" />
</ItemGroup>
<ItemGroup />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not required :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh:)

/// <summary>
/// MosaicControl is created with XAML
/// </summary>
PureXaml,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why exposing this? I understand the need to use Xaml when composition is not available (and I love this fallback) but why as an user could I change it?

Copy link
Contributor Author

@samoteph samoteph Dec 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point ! I'll change the exposition of the enum to private.

}

// Using a DependencyProperty as the backing store for ScrollViewer. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScrollViewerContainerProperty =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to keep all DP first in the file (sorry for being picky)

this.RefreshMove(this.OffsetX + this.animationX, this.OffsetY + this.animationY);
}

object lockerOffset = new object();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must define an access modifier

}
}

// retire les sprites visual en trop
Copy link
Contributor

@deltakosh deltakosh Dec 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments must be in english (But I agree with you, it is a shame :))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never again French words in this page !

/// When the control is in Design mode, Composition is not allowed.
/// </summary>
/// <returns>the UIStrategy choosed</returns>
private UIStrategy GetUIStrategy()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not a getter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remove the DP UIStrategy and replace by a simple property with a getter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect. A cool .md in the doc folder and we are good to go

@deltakosh
Copy link
Contributor

Impressive control!! Just some tiny comments and a documentation and we are good to go :)

if (rootElement != null)
{
this.rootElement = rootElement;
rootElement.SizeChanged += RootElement_SizeChanged;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OnApplyTemplate() can get called multiple times, so always safer to unhook before hooking any events in here,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the tips !

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls">
<Style TargetType="controls:MosaicControl">
<Setter Property="Template">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the benefit of Xbox One controller navigation (and keyboard navigation), can we add <Setter Property="IsTabStop" Value="False" /> to this? Whilst it's content is fine to be focusable I don't think there's any reason the container should be by default.

{
// Using a DependencyProperty as the backing store for ScrollViewer. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScrollViewerContainerProperty =
DependencyProperty.Register("ScrollViewerContainer", typeof(FrameworkElement), typeof(MosaicControl), new PropertyMetadata(null, OnScrollViewerContainerChange));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline with the style of some of the other controls in the project, you may want to consider DependencyProperty.Register(nameof(ScrollViewerContainer).... rather than DependencyProperty.Register("ScrollViewerContainer"...

(same applies for the rest of the DP's)

Copy link
Contributor

@skendrot skendrot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also: Remove uses of this.
It would be good to have an image that looks good as it's tiled.

<Grid>
<Border
x:Name="RootElement"
Background="{TemplateBinding Background}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template bind the border properties as well

/// <summary>
/// Gets or sets an X offset of the image
/// </summary>
public double OffsetX
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add new offset properties instead of just using margin?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OffsetX and OffsetY are not destined to manage the layout but the starting position of the repeated image. It's like properties AlignmentX and AlignmentY of the ImageBrush class in WPF.

public static readonly DependencyProperty AnimationDurationProperty =
DependencyProperty.Register(nameof(AnimationDuration), typeof(double), typeof(MosaicControl), new PropertyMetadata(30.0, OnAnimationDuration));

private FrameworkElement rootElement = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name private member variables with _pascalCase

/// <summary>
/// MosaicControl is created with XAML
/// </summary>
PureXaml,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why support xaml at all for something like this? Rendering and memory would be too much

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rendering with XAML has been created at first for the XAML Viewer (when it'll be functionnal ^^) and after for version that doesn't support Composition. As it use a unique ImageBrush it is not too expensive for the memory consumption and the performances are not bad.

Copy link
Contributor

@deltakosh deltakosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to go for me..

@deltakosh
Copy link
Contributor

@skendrot, @JohnnyWestlake ok for the merge?

@skendrot
Copy link
Contributor

Not too excited about the new dependency on Robmikh.CompositionSurfaceFactory

@deltakosh
Copy link
Contributor

Robert is a developer on the Windows Composition team so I'm fine with this dependency.

@samoteph
Copy link
Contributor Author

Maybe Robert would be OK to integrate his CompositionSurfaceFactory in the toolkit :)

@deltakosh
Copy link
Contributor

Ping @robmikh :)

@deltakosh
Copy link
Contributor

@samoteph
Copy link
Contributor Author

This is not a stupid question at all. In case of a Device Lost, the image must be reloaded. CompositionSurfaceFactory does all the work for us. SurfaceLoader doesn't (I guess).

@XamlBrewer
Copy link
Contributor

XamlBrewer commented Dec 15, 2016

There's also a huge performance gain: CompositionSurfaceFactory loads images a lot faster than SurfaceLoader.

@robmikh
Copy link
Contributor

robmikh commented Dec 15, 2016

Hi sorry, I missed this in the torrent of notifications! :)

I have no qualms about adding CompositionSurfaceFactory, I'm just not sure how it would work. It's currently a C++/CX component, so I'm guessing it would become its own package in a sub-namespace? Just know that I don't remember if ID3D11Device4 is an Anniversary Update interface or not, and it's what I use to get proper device lost events.

I've also recently added GetSharedSurfaceFactoryForCompositor so that it's easier for multiple components to all use the same SurfaceFactory object. That way there will only be one D3D device created by the app.

@deltakosh
Copy link
Contributor

deltakosh commented Dec 15, 2016

No worry :)
@shenchauhan Do you think you can use @robmikh code to support DeviceLost? (I try to define if we can avoid this external dependency and only use your SurfaceLoader)
If we cannot (And base on @XamlBrewer mention there is also a perf issue), we should remove the SurfaceLoader and only use CompositionSurfaceFactory

@samoteph
Copy link
Contributor Author

Up :)

@deltakosh
Copy link
Contributor

I think @shenchauhan is working on removing surfaceloader

@deltakosh
Copy link
Contributor

it 's a go for me. just a second reviewer

@deltakosh
Copy link
Contributor

Do you mind removing conflicts? (pretty please :))

@samoteph
Copy link
Contributor Author

samoteph commented Jan 3, 2017

Done ?

@deltakosh
Copy link
Contributor

ok trying to summon another reviewer:) I'll merge else

@samoteph
Copy link
Contributor Author

samoteph commented Jan 3, 2017

Oky :)

Copy link
Contributor

@shenchauhan shenchauhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of comments around styling and also possibly consider using parallax that we will be shipping in the toolkit.

/// </summary>
public sealed class MosaicControl : ContentControl
{
private FrameworkElement rootElement = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the .NET Core coding stlyes mentioned here: https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md

so it should be _rootElement

/// <param name="e">arguments</param>
private async void RootElement_SizeChanged(object sender, SizeChangedEventArgs e)
{
Debug.WriteLine("sizeChanged=" + e.NewSize.Width);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the Debug.WriteLine

{
var speedRatio = this.ParallaxSpeedRatio;

scrollX = -((scrollviewer.HorizontalOffset * scrollviewer.ActualWidth) / scrollviewer.ViewportWidth) * speedRatio;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it better to use the parallax behavior that's going into the Toolkit? (I think there is a PR for it already) This way there is a consistent way for people to adjust the parallax effect across the toolkit. Appreciate that the PR hasn't gone through yet, but thought I would ask the question here in case you weren't aware.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the Mosaic control integrate an infinite scrolling effect. this is made by using a Composition expression. this expression manage the offset modulo (included negative value) of the scrolling. This expression is used for manual move (OffsetX, OffsetY) + parallax effect and this is the core of the control. The parallax Service is a great helper to create quickly a parallax effect but in this case the scenario is too complicated I think for be used internally.

@deltakosh
Copy link
Contributor

Do you mind removing conflicts? (pretty please :))
I promise to merge after that :)

Copy link
Contributor

@shenchauhan shenchauhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! 👍 Nice control.

@shenchauhan shenchauhan merged commit c1c72e3 into CommunityToolkit:dev Jan 5, 2017
@samoteph
Copy link
Contributor Author

Thanks guys !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants