Maxime FRAPPAT

Hum …no thanks ! – Lordinaire

Category: C# (Page 2 of 13)

Working with Docker in Visual Studio 2017

Docker is a well-know tool in Microsoft ecosystem since few years. You can of course doing great things if you deal with Azure but it isn’t limited to “ops”. Developers can now easily play with Docker inside Visual Studio with some additional tools. Stuff like starting a container becomes so easy that everybody must use it! (I like Docker, a lot!)

Setup & Tools

First, you need to download and install Docker for Windows and select the .NET Core option in the installer of Visual Studio 2017.

Bonus: You can additionally download Kitematic (Visual Docker Container Management) if the CLI is not your friend.

Project sample

Let’s create a new ASP.NET Core 2.0 project of type WebAPI. The main benefit to target a .NET Core project is that it can run on Windows AND Linux platform.

Docker for Windows is able to run both of platforms type for a container but not a mixed use of it. So, you need that all your containers target the same platform, you can’t set a specific platform for a container. That’s the only limitation that I face off (and it can be a huge one…).

You can check the Enable Docker Support now or add it after when the solution will be created. If you doesn’t set the option, le solution explorer looks like that :

To activate the Docker support, right clic on the project and select Add > Enable Docker Support. Visual Studio will now automatically create a new project named docker-compose and a Dockerfile in your project. Well, thank you VS.

Dockerfile

FROM microsoft/aspnetcore:2.0
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

docker-compose.yml

version: '3'

services:
  webapplication1:
    image: webapplication1
  build:
    context: ./WebApplication1
    dockerfile: Dockerfile

Start the project

Before starting the project, we need to check if the shared drives settings are set properly because Docker required full access to drives where the source code.

Update 04/11/17 : This is only needed if you use Linux containers with Docker for Windows. You can avoid that by using the option Switching to Windows containers.

 

To run your project with Docker, you need to set the docker-compose project as startup project. Hit F5 and open the console window : you will see all the steps like downloading the image, creating the container, …

Bonus: You can add breakpoints like you always do and it will work!

Bonus 2: If you launch Kitematic you will see your container with all his settings

 

 

 

[UWP] FlyoutView control

In a project, I needed a control like the old SettingsFlyout which is now obselete. What I wanted is just a panel that come-and-go with a great animation.

Style


<Style TargetType="flyoutView:FlyoutView">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="flyoutView:FlyoutView">
                <Grid>
                    <Grid x:Name="PART_OVERLAY" Background="{TemplateBinding BackgroundOverlay}" Visibility="Collapsed" />

                    <Grid x:Name="PART_CONTENT">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition />
                        </Grid.RowDefinitions>

                        <Grid.RenderTransform>
                            <CompositeTransform />
                        </Grid.RenderTransform>

                        <ContentControl ContentTemplate="{TemplateBinding HeaderTemplate}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" />

                        <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}" />
                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The logic

We need to create the storyboards by hand because the content width/height aren’t static.

[TemplatePart(Name = PartOverlay, Type = typeof(Grid))]
[TemplatePart(Name = PartContent, Type = typeof(Grid))]
public partial class FlyoutView : ContentControl
{
    #region Dependency properties

    public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register(
            "HeaderTemplate", typeof(DataTemplate), typeof(FlyoutView),
            new PropertyMetadata(default(DataTemplate)));

    public DataTemplate HeaderTemplate
    {
        get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
        set { SetValue(HeaderTemplateProperty, value); }
    }

    public static readonly DependencyProperty PlacementProperty = DependencyProperty.Register(
        "Placement", typeof(PlacementType), typeof(FlyoutView),
        new PropertyMetadata(default(PlacementType), OnPlacementChanged));

    public PlacementType Placement
    {
        get { return (PlacementType)GetValue(PlacementProperty); }
        set { SetValue(PlacementProperty, value); }
    }

    public static readonly DependencyProperty UseDismissOvelayProperty = DependencyProperty.Register(
        "UseDismissOvelay", typeof(bool), typeof(FlyoutView),
        new PropertyMetadata(default(bool)));

    public bool UseDismissOvelay
    {
        get { return (bool)GetValue(UseDismissOvelayProperty); }
        set { SetValue(UseDismissOvelayProperty, value); }
    }

    public static readonly DependencyProperty BackgroundOverlayProperty = DependencyProperty.Register(
        "BackgroundOverlay", typeof(SolidColorBrush), typeof(FlyoutView),
        new PropertyMetadata(default(SolidColorBrush)));

    public SolidColorBrush BackgroundOverlay
    {
        get { return (SolidColorBrush)GetValue(BackgroundOverlayProperty); }
        set { SetValue(BackgroundOverlayProperty, value); }
    }

    public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
            "IsOpen", typeof(bool), typeof(FlyoutView),
            new PropertyMetadata(default(bool), OnIsOpenChanged));

    public bool IsOpen
    {
        get { return (bool)GetValue(IsOpenProperty); }
        set { SetValue(IsOpenProperty, value); }
    }

    public static readonly DependencyProperty ContentWidthProperty = DependencyProperty.Register(
        "ContentWidth", typeof(double), typeof(FlyoutView),
        new PropertyMetadata(default(double)));

    public double ContentWidth
    {
        get { return (double)GetValue(ContentWidthProperty); }
        set { SetValue(ContentWidthProperty, value); }
    }

    public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(
        "ContentHeight", typeof(double), typeof(FlyoutView),
        new PropertyMetadata(default(double)));

    public double ContentHeight
    {
        get { return (double)GetValue(ContentHeightProperty); }
        set { SetValue(ContentHeightProperty, value); }
    }

    #endregion

    #region Properties

    public enum PlacementType
    {

        Left,
        Top,
        Right,
        Bottom
    }

    private const string PartOverlay = "PART_OVERLAY";
    private const string PartContent = "PART_CONTENT";

    private Storyboard _openStoryboard;
    private Storyboard _closeStoryboard;
    private Grid _content;
    private Grid _overlay;

    #endregion

    #region Constructor

    public FlyoutView()
    {
        DefaultStyleKey = typeof(FlyoutView);
    }

    #endregion

    #region Override

    protected override void OnApplyTemplate()
    {
        _overlay = GetTemplateChild(PartOverlay) as Grid;
        _content = GetTemplateChild(PartContent) as Grid;

        if (_content != null)
        {
            _content.Loaded += OnContentLoaded;
            HandleOpening();
        }

        if (_overlay != null)
            _overlay.Tapped += OnOverlayTapped;

        UpdateFromLayout();

        base.OnApplyTemplate();
    }

    #endregion

    #region Methods

    private void UpdateFromLayout()
    {
        if (_content == null || _overlay == null)
            return;

        double overflow;
        if (Placement == PlacementType.Left
            || Placement == PlacementType.Right)
            overflow = Placement == PlacementType.Left
                ? -ContentWidth
                : ContentWidth;
        else
            overflow = Placement == PlacementType.Top
                ? -ContentHeight
                : ContentHeight;

        UpdatePlacement(overflow);
        UpdateAnimations(overflow);
    }

    private void UpdatePlacement(double overflow)
    {
        if (Placement == PlacementType.Left
            || Placement == PlacementType.Right)
        {
            _content.Width = ContentWidth;
            _content.Height = double.NaN;
            _content.RenderTransform = new CompositeTransform { TranslateX = overflow, TranslateY = 0 };
            _content.HorizontalAlignment = Placement == PlacementType.Left
                ? HorizontalAlignment.Left
                : HorizontalAlignment.Right;
            _content.VerticalAlignment = VerticalAlignment.Stretch;
        }
        else
        {
            _content.Width = double.NaN;
            _content.Height = ContentHeight;
            _content.RenderTransform = new CompositeTransform { TranslateX = 0, TranslateY = overflow };
            _content.VerticalAlignment = Placement == PlacementType.Top
                ? VerticalAlignment.Top
                : VerticalAlignment.Bottom;
            _content.HorizontalAlignment = HorizontalAlignment.Stretch;
        }
    }

    private void UpdateAnimations(double overflow)
    {
        var targetProperty = Placement == PlacementType.Left || Placement == PlacementType.Right
            ? "(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
            : "(UIElement.RenderTransform).(CompositeTransform.TranslateY)";

        // Create animations
        _openStoryboard = new Storyboard();
        var openAnimation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(500),
            From = overflow,
            To = 0,
            EasingFunction = new PowerEase { EasingMode = EasingMode.EaseIn, Power = 2 }
        };
        Storyboard.SetTargetProperty(openAnimation, targetProperty);
        Storyboard.SetTarget(openAnimation, _content);
        _openStoryboard.Children.Add(openAnimation);

        _closeStoryboard = new Storyboard();
        var closeAnimation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(500),
            From = 0,
            To = overflow,
            EasingFunction = new PowerEase { EasingMode = EasingMode.EaseOut, Power = 2 }
        };
        Storyboard.SetTargetProperty(closeAnimation, targetProperty);
        Storyboard.SetTarget(closeAnimation, _content);
        _closeStoryboard.Children.Add(closeAnimation);
    }

    #endregion

    #region Events

    private void OnContentLoaded(object sender, object o)
    {
        _content.Loaded -= OnContentLoaded;

        UpdateFromLayout();
    }

    private void OnOverlayTapped(object sender, TappedRoutedEventArgs e)
    {
        if (IsOpen)
            IsOpen = false;
    }

    private static void OnIsOpenChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var control = sender as FlyoutView;

        control?.HandleOpening();
    }

    private void HandleOpening()
    {
        if (IsOpen)
        {
            if (UseDismissOvelay)
                _overlay.Visibility = Visibility.Visible;

            _openStoryboard?.Begin();
        }
        else
        {
            if (UseDismissOvelay)
                _overlay.Visibility = Visibility.Collapsed;

            _closeStoryboard?.Begin();
        }
    }

    private static void OnPlacementChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var control = sender as FlyoutView;

        control?.UpdateFromLayout();
    }

    #endregion
}

Usage

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Image Width="300" Height="300" Source="ms-appx:///Assets/ToolkitLogo.png" />

    <flyoutView:FlyoutView IsOpen="{Binding Path=IsOpen.Value, Mode=TwoWay}" Placement="{Binding Path=Placement.Value, Mode=TwoWay}" UseDismissOvelay="True" BackgroundOverlay="#BBF0F0F0" ContentWidth="300" ContentHeight="150">
        <flyoutView:FlyoutView.HeaderTemplate>
            <DataTemplate>
                <Grid Background="{StaticResource Brush-Grey-02}">
                    <TextBlock Text="{Binding Path=Header.Value}" Style="{StaticResource HeaderTextBlockStyle}" Margin="20" />
                </Grid>
            </DataTemplate>
        </flyoutView:FlyoutView.HeaderTemplate>

        <Grid Background="{StaticResource Brush-Grey-03}">
            <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="This is the content" VerticalAlignment="Center" Style="{StaticResource SubtitleTextBlockStyle}" />
        </Grid>
    </flyoutView:FlyoutView>
</Grid>

Demo

Page 2 of 13

Powered by WordPress & Theme by Anders Norén

%d bloggers like this: