2011年5月11日

Add an uninstall shortcut to setup project

使用 VS2010 建立 WPF 的 Setup Project,若希望在程式集的錄下,有一個解除安裝的按鈕,可以採用下列的方法。

  1. 在 Setup Project 的 User's Programs Menu 點選右鍵,選擇 Add / Project Output / Primary Output,並將名稱改為 Unstall xxx
  2. 將此 Shortcut 的 Argument 屬性設為 /u=[ProductCode]
  3. 上列設定將產生 unstall 項目,並在點選後,呼叫原 AP 程式,並帶入 /u=[ProductCode] 參數。參數中的 ProductCode 會自動轉換成 AP 的 guid。接著將下列的程式碼加到 WPF 的 App.xaml.cs 的 OnStartup(),來實際執行 unstall 的工作。

 
protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    // 解除安裝
         string[] arguments = Environment.GetCommandLineArgs();
    foreach (string argument in arguments)
    {
        string[] items = argument.Split(new char[] { '=' });
        if (items.Length >= 2 && items[0].ToLower() == "/u")
        {
            string guid = items[1];
            string path = Environment.GetFolderPath(Environment.SpecialFolder.System);
            ProcessStartInfo info = new ProcessStartInfo(path + @"\msiexec", "/x" + guid); 
            Process.Start(info);
            this.Shutdown();
        }
    }
}
[Reference]
Add an uninstall start menu item to your .NET deployment project

2011年5月5日

WPF TileBrush

WPF 的 TileBrush 有 BrushMappingMode.Absolute 與 BrushMappingMode.RelativeToBoundingBox 兩種模式:

Absolute 採用固定的像數,Tile 圖案不會隨著物件的伸展而改變大小與形狀:



RelativeToBoundingBox 則相對於物件的長寬比,因此數量是不變的:



除了 TileBrush.ViewportUnits 設定的差異外,若 Tile 的圖案採用向量而不是圖檔時,要特別注意 Absolute 的用法。Absolute 以像數計算,DrawingBrush 會畫不出東西來,必須轉成 ImageBrush 才能正常運作,以下是這兩段程式的差異。

BrushMappingMode.RelativeToBoundingBox:
 
        public MainWindow()
        {
            InitializeComponent();

            Rectangle exampleRectangle = new Rectangle();

            GeometryDrawing backgroundSquare =
                new GeometryDrawing(Brushes.White, null, new RectangleGeometry(new Rect(0, 0, 100, 100)));

            GeometryGroup aGeometryGroup = new GeometryGroup();
            aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(0, 0, 50, 50)));
            aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(50, 50, 50, 50)));

            LinearGradientBrush checkerBrush = new LinearGradientBrush();
            checkerBrush.GradientStops.Add(new GradientStop(Colors.Black, 0.0));
            checkerBrush.GradientStops.Add(new GradientStop(Colors.Gray, 1.0));

            GeometryDrawing checkers = new GeometryDrawing(checkerBrush, null, aGeometryGroup);

            DrawingGroup checkersDrawingGroup = new DrawingGroup();
            checkersDrawingGroup.Children.Add(backgroundSquare);
            checkersDrawingGroup.Children.Add(checkers);

            DrawingBrush myBrush = new DrawingBrush();
            myBrush.Drawing = checkersDrawingGroup;
            myBrush.ViewboxUnits = BrushMappingMode.RelativeToBoundingBox;
            myBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
            myBrush.TileMode = TileMode.Tile;
            exampleRectangle.Fill = myBrush;

            TilePanel.Children.Add(exampleRectangle);
        }



BrushMappingMode.Absolute:
 
        public MainWindow()
        {
            InitializeComponent();

            Rectangle exampleRectangle = new Rectangle();

            GeometryDrawing backgroundSquare =
                new GeometryDrawing(Brushes.White, null, new RectangleGeometry(new Rect(0, 0, 100, 100)));

            GeometryGroup aGeometryGroup = new GeometryGroup();
            aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(0, 0, 50, 50)));
            aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(50, 50, 50, 50)));

            LinearGradientBrush checkerBrush = new LinearGradientBrush();
            checkerBrush.GradientStops.Add(new GradientStop(Colors.Black, 0.0));
            checkerBrush.GradientStops.Add(new GradientStop(Colors.Gray, 1.0));

            GeometryDrawing checkers = new GeometryDrawing(checkerBrush, null, aGeometryGroup);

            DrawingGroup checkersDrawingGroup = new DrawingGroup();
            checkersDrawingGroup.Children.Add(backgroundSquare);
            checkersDrawingGroup.Children.Add(checkers);

            DrawingImage image = new DrawingImage(checkersDrawingGroup);
            ImageBrush myBrush = new ImageBrush(image);
            myBrush.Stretch = Stretch.None;
            myBrush.TileMode = TileMode.Tile;
            myBrush.Viewport = new Rect(0, 0, 100, 100);
            myBrush.ViewportUnits = BrushMappingMode.Absolute;
            exampleRectangle.Fill = myBrush;

            TilePanel.Children.Add(exampleRectangle);
        }

[Reference]
WPF Brushes Overview
ImageBrush for a BackGround grid in WPF

Deploying Vue & .NET with Google OAuth on GCP Cloud Run

Deploying Vue & .NET with Google OAuth on GCP Cloud Run Deploying Vue & .NET with Google OAuth on GCP Cloud Run...