반응형

Oracle DB의 테이블을 이용해서 Join하는 방법을 알아보겠습니다.

 

1. 모델 정의

1:N관계에서 N쪽 테이블(TempDataroomHstry클래스)에 ForeignKey로 1쪽 테이블명(Temp래스)을 지정해줍니다. 이때, 1쪽 테이블의 참조하려는 필드가 Primary Key로 지정되어있으면 상관없지만, 없을 경우 필드 정의에(ForeignKey 함수 내부에서) to__field='목표필드' 를 지정해줘야 합니다. 그리고, db_column='참조칼럼명' 에서 해당 테이블에서 참조할 실제 칼럼(필드)명을 지정해줘야 합니다.

 

(*) Oracle DB에서만 이런 문제가 발생하는 것인지.. 아직은 잘 모르겠습니다. 이것 때문에 한참을 헤메었네요..^^;; 또한 이번의 경우 Temp의 emp_field와 TempDataroomHstry의 id는 사실 칼럼명은 동일하게 'emp_#'이었습니다. db_column에 넣어주는 값이 현재 테이블의 칼럼명인지, 목표 테이블의 칼럼명인지 좀 헷갈립니다...

<models.py>

from django.db import models


class Temp(models.Model):
    emp_field = models.CharField(db_column='emp_#', primary_key=True, max_length=7)  # Field renamed to remove unsuitable characters. Field renamed because it ended with '_'.
    emp_x = models.CharField(max_length=2, blank=True, null=True)
    kornm_n = models.CharField(max_length=32, blank=True, null=True)    
    res_1 = models.CharField(db_column='res_#1', max_length=12, blank=True, null=True)  # Field renamed to remove unsuitable characters.    
    sex_n = models.CharField(max_length=2, blank=True, null=True)    
    dept_c = models.CharField(max_length=16, blank=True, null=True)
    
    class Meta:
        managed = False
        db_table = 'TEMP'


class TempDataroomHstry(models.Model):
    seq_field = models.IntegerField(db_column='seq_#',primary_key=True)  # Field renamed to remove unsuitable characters. Field renamed because it ended with '_'.
    id = models.ForeignKey(Temp, to_field='emp_field', db_column='emp_#',on_delete=models.CASCADE, null=True, related_name='id')   #, related_name='tempdataroomhstry'
    in_d = models.DateField(blank=True, null=True)


    class Meta:
        managed = False
        db_table = 'TEMP_DATAROOM_HSTRY'

 

2. 데이터 활용하기

Join을 위해서는 "select_related()"나 "prefetch_related()"를 사용하는데, 이번에는 select_related()만 알아보도록 하겠습니다. select_related는 1:1 또는 1:N 의 경우에 사용할 수 있는 함수입니다. (정방향 참조필드). select_related()의 인자로는 해당 Table의 ForeinKey를 넣어줍니다. 아래의 예제에서는 우선 'id'칼럼을 이용하여 join후 모든 데이터를 불러오고 'in_d'를 기준으로 역정렬(desc)을 하여 list를 만들고, 이를 home.html에 넘겨줍니다.

<views.py>

from django.core.paginator import Paginator
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse

from .models import TempDataroomHstry

#### 초기화면 및 조회함수 ####
def index(request):
    list = {}
    list = TempDataroomHstry.objects.select_related('id').all().order_by('-in_d')

    # HTML에서 인자가 전달될 경우 처리
    q = request.GET.get('q', '')
    if q:
        list = list.filter(id=q)
    # 여기까지
   
    context = {'member_list': list}
    return render(request, 'home.html', context)

A테이블에 B가 조인될 경우 "[A].[조인된A칼럼명].[B칼럼명]"과 같이 사용하면 됩니다. 아래 home.html파일은 실제 Join된 데이터를 불러와 사용하는 예시를 볼 수 있습니다.

<home.html>

....
<tbody>
{% if member_list %}
  {% for member in member_list %}
    <tr>
      <td>{{ member.id.emp_field }}</td>
      <td>{{ member.id.kornm_n }}</td>
      <td>{{ member.id.res_1 }}</td>
      <td>{{ member.id.sex_n }}</td>
      <td>{{ member.id.dept_c }}</td>
      <td>{{ member.in_d }}</td>
    </tr>
  {% endfor %}
{% endif %}
</tbody>

 

~~~끝~~~

반응형
반응형

이번에는 Webview 라이브러리를 사용하면서 HTML 파일을 별도로 분리하는 방법을 알아보겠습니다. 그리고, 좀더 보기좋은 GUI 구성을 위해 부트스트랩도 함께 적용하도록 하겠습니다. 사실 이부분은...CSS 파일을 별도로 인식시켰으면 좋겠지만, 아직까지 별도의 CSS파일을 적용시키는 것은 안되는 것 같습니다. 

 

1. 라이브러리 설치

라이브러리 설치는 이전 강좌를 참고하세요.

 

2. main.go 파일 작성

main.go 파일에 전체 프로그램 구동을 구현합니다. 아울러, 버튼을 클릭했을 때 동작할 함수(go_hello)를 작성하고, 바인딩해줍니다. Webview라이브러리를 활용하면, go에서 javascript를 실행할 수도 있고, html파일(javascript 포함)에서 go언어를 실행할 수도 있습니다. 그러나 프로그램 가독성을 위해, Bind 한줄이 더 들어가더라도, 함수구현은 go에서 하도록 하겠습니다.

package main

import (
	"fmt"
	"os"

	"github.com/webview/webview"
)

var w webview.WebView

func main() {
	w = webview.New(true)
	defer w.Destroy()
	w.SetSize(600, 600, webview.HintNone) // Create a GoLang function callable from JS
	w.Bind("go_hello", go_hello)	// Go_hello 함수 구현과 html에서 호출하는 go_hello를 Bind해줍니다. 

	// Create UI with data URI
	dir, _ := os.Getwd()
	fmt.Println(dir)
	w.Navigate("file:" + dir + "/hi.html")

	w.Run()
}

// 함수 실행 시, javascript로 팝업 알람을 실행해서 데이터를 보여줍니다.
// HTML문서에서 보여주는 부분만큼은...javascript로..ㅠㅠ
func go_hello() {
	name := "You"
	w.Eval(`alert("Hello` + name + `");`)
}

데이터를 처리하는 것은 go 함수구현에서 할 수 있지만, 마지막으로 데이터를 HTML로 보내서 보여주는 부분은 Javascript로 할 수밖에 없겠네요..^^;;

 

3. hi.html

HTML로 뷰를 구현합니다. 서두에서 말했듯이 CSS 적용이 힘든 관계로 Bootstrap을 CDN으로 불러와 적용시키겠습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

    <title>My App</title>
</head>
<body>
    <!--Header Section-->
    <div class="box-padding-big">
      <nav class="navbar navbar-expand-sm navbar-dark bg-dark">
        <div class="collapse navbar-collapse">
          <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
              <a class="nav-link" href="#" id=navbardrop" data-toggle="dropdown">File</a>
              <div class="dropdown-menu">
              <a class="dropdown-item" href="#" onclick="go_hello()">Sub1</a>
              <a class="dropdown-item" href="#">Sub2</a>
              <a class="dropdown-item" href="#">Sub3</a>
              </div>
            </li>
            <li class="hav-item">
            	<a class="nav-link" href="#">Edit</a>
            </li>
            <li class="hav-item">
            	<a class="nav-link" href="#">View</a>
            </li>
            <li class="hav-item">
            	<a class="nav-link" href="#">Info</a>
            </li>
          </ul>
        </div>
      </nav>
    </div>

  <!--Main Section-->
  <div style="margin: 20px;">
  	<div style="font-size: 36px; color:chartreuse;font-weight:700">
      <div>GO-Webview HTML View Test <br/>
      with Bootstrap
      </div>
    </div>
    <p class="text-primary" style="margin-top:20px;">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget magna eros. Cras sit amet nulla dignissim, pretium justo sit amet, vulputate orci. Curabitur in aliquam lorem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi quis pulvinar nunc, sed posuere enim. In hac habitasse platea dictumst. Ut sodales augue eu elit bibendum, ut malesuada felis auctor. Sed mattis ipsum malesuada sem feugiat ultricies. Fusce ultrices vel est id pretium. Sed vel congue augue, non tincidunt tellus. Vivamus facilisis mollis tellus ac vulputate. 
    </p>
  </div>
</body>
</html>

 

4. 결과

아래 명령으로 결과를 확인합니다.

go run main.go

File - Sub1을 클릭하면...

알람 팝업이 잘 나옵니다.

 

이상으로 webview를 이용하여 html 파일과 bootstrap을 적용하는 방법을 알아봤습니다. 너무 쉽게 구현이 가능한데, 성능은 어느정도일지, 어떤 점이 부족할지 계속 알아봐야겠습니다.

 

~~~끝~~~

반응형
반응형

Go언어 GUI 라이브러리 중 Webview를 사용해서 데스크탑 앱을 만들어보도록 하겠습니다. Webview는 HTML로 레이아웃을 구성할 수 있어서 간단한 앱은 쉽게 만들 수 있습니다.

 

1. 라이브러리 설치

이번엔 리눅스환경에서(우분투 20.04) 라이브러리를 설치하겠습니다. 

sudo apt-get install libgtk-3-dev
sudo apt-get install libwebkit2gtk-4.0-dev

go get github.com/webview/webview

2. Sample Project

다음으로 간단히 main.go 파일을 생성하고, 아래와 같이 작성해줍니다.

package main

import "github.com/webview/webview"

func main() {
	w := webview.New(true)
	defer w.Destroy()
	w.SetSize(600, 200, webview.HintNone) // Create a GoLang function callable from JS
	w.Bind("hello", func() string { return "World!" })

	// Create UI with data URI
	w.Navigate(`data:text/html,
	 <!doctype html>
	 <html>
	  <head><title>Hello</title></head>
	  <body><h1>Hello, world!</h1></body>
	  <script> hello().then((x) => { console.log(x) }) </script>
	 </html>`)

	w.Run()
}

 

3. 실행

터미널에서 아래와 같이 명령하면..

go run main.go

이쁜 앱이 나타났습니다. 라이브러리만 설치하면 프로그램 작성은 정말 쉽게 할 수 있네요.

 

이상으로  Golang에서 Webview 라이브러리를 이용한 GUI개발을 알아봤습니다. 

다음번엔 HTML 파일을 분리하여 작성하는 방법을 알아보겠습니다.

 

~~~끝~~~

반응형
반응형
import pandas as pd
import requests
from bs4 import BeautifulSoup

key = '내 서비스키'
# url='http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade?LAWD_CD=11110&DEAL_YMD=201512&serviceKey='+key
url='http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade?serviceKey='+key

rowList=[]  # 전체 행을 저장할 변수
nameList=[] # 열(칼럼) 이름을 저장할 변수
item_content=[] # 각 행별 칼럼값들을 저장할 임시공간

# 지역코드는 11000(서울)~39020(서귀포)
city_list=["26440","26410","26710","26290","26170","26260","26230","26320","26530","26380","26140","26500","26470","26200","26110","26350"]
for city in city_list:
    params ={'LAWD_CD' : city, 'DEAL_YMD' : '202110' } 
    response = requests.get(url, params=params).text #인코딩이 필요할 경우 .encode('utf-8')
    
    soup = BeautifulSoup(response, "lxml-xml")

    item_list = soup.find_all('item')   # 전체 contents를 담은 변수
    
    rowsLen = len(item_list)    # 전체 행 수
    for i in range(rowsLen):
        columns = item_list[i].find_all() # 1번째 행(row)의 모든 요소값들을 칼럼으로 한다.
        columnsLen = len(columns)    # 1번째 행(row)의 요소길이를 열(column) 길이로 한다.

        for j in range(0, columnsLen):
            if i == 0 and city=="26440":    # 첫번째 행 데이터 수집시 컬럼 값 저장
                nameList.append(columns[j].name)    # name 값만 추출한다

            eachColumn = columns[j].text    # 각 행(i)의 각 열(j)의 텍스트만 추출한다.
            item_content.append(eachColumn)   # 각 칼럼값을 append하여 1개 행을 만든다.
        rowList.append(item_content)    # 전체 리스트 공간에 개별 행을 append한다.
        item_content=[] # 다음 row의 값을 입력받기 위해 비워준다.

df = pd.DataFrame(rowList, columns=nameList)
df.head(50)

반응형
반응형

회사에서 Visual Studio를 안사주는데, GUI 프로그래밍은 해야겠고...

Visual Studio Code를 이용해 Dotnet Core로 프로그래밍을 하다보니 Resource 추가하는 것도 쉽지 않네요. 잊기전에 적어놓습니다. 예를 들어 아래와 같이 ./Resources 라는 폴더를 프로젝트에 추가할 경우..

 

.csproj 파일에 <Content> 태그 부분을 추가해줍니다.

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
	<PropertyGroup>
		<OutputType>WinExe</OutputType>
		<TargetFramework>netcoreapp3.1</TargetFramework>
		<UseWPF>true</UseWPF>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="MaterialDesignThemes" Version="4.2.1"/>
		<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.11">
			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
			<PrivateAssets>all</PrivateAssets>
		</PackageReference>
		<PackageReference Include="Oracle.EntityFrameworkCore" Version="5.21.4"/>
		<PackageReference Include="System.Data.SqlClient" Version="4.8.3"/>
		<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.11"/>
		<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.11"/>
		<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.11"/>
        
		<!-- 추가 -->
		<Content Include="Resources\*.*">
			<CopyToOutputDirectory>Always</CopyToOutputDirectory>
		</Content>
		<!-- 여기까지 -->
        
	</ItemGroup>	
</Project>

 

이제 xaml파일에서 "\Resources\Image.jpg"와 같이 접근할 수 있습니다.

(이거 잘 생각 안나면 절대경로로 하면 작동은 합니다.)

반응형
반응형

오늘은 아래 유튜브 영상의 데스크탑 어플리케이션을 구현해보겠습니다.

https://www.youtube.com/watch?v=qSP8v8Gi3XU

 

1. 라이브러리 설치

이번 영상에서는 Material Design과 LiveCharts를 사용합니다. 아래의 명령으로 Package를 설치해줍니다.

dotnet add package MaterialDesignThemes --version 4.2.1 // material Design 설치
dotnet add package LiveCharts.Wpf --version 0.9.7 // live chart 설치

또는 Nuget GUI Manager 를 설치 후

 

Shift + Ctrl + P 로 명령창에서 Nuget 입력 시 나타나는 명령을 수행합니다.

그리고 Nuget Package Manager에서 아래와 같이 설치해줍니다. Material Design Themes와 Livecharts.wpf로 검색되는 패키지를 설치해줍니다.

귀차니즘....끄적끄적..

 

2. 라이브러리 적용

Material Design을 적용해야합니다. 적용하는 방법은 구글에서 < material design xaml >이라고 검색하면 나오는데, 여기 사이트를 참조하시면 되겠습니다. 그리고, 나중에 livechart에서 사용할 스타일도 정의해놓겠습니다.

<App.xaml>

<Application x:Class="wpf_test04UT2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wpf_test04UT2"
             xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <Style TargetType="lvc:LineSeries">
                <Setter Property="StrokeThickness" Value="3"></Setter>                
                <Setter Property="Fill" Value="#4EFFFFFF"></Setter>                
                <Setter Property="PointGeometrySize" Value="0"></Setter>
                <Setter Property="LineSmoothness" Value="0"></Setter>
            </Style>
            <Style TargetType="lvc:Axis">
                <Setter Property="ShowLabels" Value="False"></Setter>                
                <Setter Property="IsEnabled" Value="False"></Setter>                                
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

3. 메인프레임 구성

메인 프레임에서는 전체적인 틀을 Grid 레이아웃으로 잡아주고, 좌측 그리드에 메뉴를 Material Design Icon으로 구성합니다.

<MainWindow.xaml>

<Window x:Class="wpf_test04UT2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:wpf_test04UT2"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        mc:Ignorable="d"
        Title="MainWindow" Height="850" Width="1200"
        WindowStartupLocation="CenterScreen"        
        WindowStyle="None"
        Background="{x:Null}"
        AllowsTransparency="True" Loaded="Window_Loaded">
    <Grid>
        <materialDesign:Card Margin="10" UniformCornerRadius="15">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="15*" />
                </Grid.ColumnDefinitions>
                <Grid.Resources>
                    <Style TargetType="materialDesign:PackIcon">
                        <Setter Property="Width" Value="30"></Setter>
                        <Setter Property="Height" Value="30"></Setter>
                    </Style>
                </Grid.Resources>
                <Grid Grid.Column="0">
                    <ListView Margin="0 15">
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="Resistor" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="CircleSlice6" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="CalendarBlankOutline" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="EqualiserVertical" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="ChatOutline" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                        <ListViewItem HorizontalAlignment="Center" Margin="0 60 0 0">
                            <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left" 
                            BorderBrush="{x:Null}" Foreground="Black" x:Name="btnExit" Click="btnExit_click">
                                <StackPanel Margin="-5">
                                    <materialDesign:PackIcon Kind="ExitToApp" />
                                </StackPanel>
                            </Button>
                        </ListViewItem>
                    </ListView>
                </Grid>
                <Grid Grid.Column="1" Background="#f6f5f8" Name="RenderPages">
                
                </Grid>
            </Grid>
        </materialDesign:Card>
    </Grid>
</Window>

이번 과제는 UI에 집중되어 있어서, cs파일에서는 별로 할일이 없습니다.

<MainWindow.xaml.cs>

using System.Windows;

namespace wpf_test04UT2
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            RenderPages.Children.Clear();
            RenderPages.Children.Add(new Dashboard());
        }
        private void btnExit_click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }
    }
}

 

4. 내부 Dashboard 작성

메인프레임에 뿌려줄 '내부'를 별도파일(UserControl)로 구현합니다. Material Design 사용하니까 이쁘고 좋긴 한데, 코드가 길어지고....익숙해지는데 시간이 좀 필요하겠네요..

<Dashboard.xaml>

<UserControl x:Class="wpf_test04UT2.Dashboard"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:wpf_test04UT2"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.wpf"
        mc:Ignorable="d"
        Height="850" Width="1100">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="8*" />
        <ColumnDefinition Width="4*" />
      </Grid.ColumnDefinitions>
      <Grid.Resources>
        <Style TargetType="materialDesign:PackIcon">
          <Setter Property="Width" Value="30"></Setter>
          <Setter Property="Height" Value="30"></Setter>
        </Style>
      </Grid.Resources>
      <Grid Grid.Column="0" Background="#f6f6f8">
        <StackPanel Margin="10">
            <Grid Height="60">
              <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left"
              BorderBrush="{x:Null}" Background="{x:Null}">
                <StackPanel Margin="5">
                  <materialDesign:PackIcon Kind="ReorderHorizontal" Foreground="Gray" />
                </StackPanel>
              </Button>
              <ComboBox HorizontalAlignment="Right" Width="100" materialDesign:HintAssist.Hint="Last 15 Days">
                <ComboBoxItem>
                  <TextBlock Text="Last 15 Days" />
                </ComboBoxItem>
                <ComboBoxItem>
                  <TextBlock Text="Last 30 Days" />
                </ComboBoxItem>
              </ComboBox>
            </Grid>
            <WrapPanel HorizontalAlignment="Center">
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Twitter" Foreground="#29A3EC" />
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="280K" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Follwers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Instagram">
                      <materialDesign:PackIcon.Foreground>
                        <LinearGradientBrush StartPoint="1,0" EndPoint="0.5,1">
                          <GradientStop Color="#912A73" Offset="0" />
                          <GradientStop Color="#FA8E22" Offset="1" />
                        </LinearGradientBrush>
                      </materialDesign:PackIcon.Foreground>
                    </materialDesign:PackIcon>
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="690K" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Followers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Youtube" Foreground="#29A3EC" />
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="2.3M" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Follwers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
              <Border BorderBrush="White" BorderThickness="5" Margin="20 0" CornerRadius="15">
                <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth0" UniformCornerRadius="15" BorderThickness="5"
                BorderBrush="White" Width="110" Height="130" Background="#F6F6F8">
                  <StackPanel Margin="10">
                    <materialDesign:PackIcon Kind="Facebook" Foreground="#29A3EC" />
                    <TextBlock FontWeight="SemiBold" FontSize="25" Text="60K" Margin="0 10 0 0" />
                    <TextBlock FontSize="12" Text="Follwers" />
                    <materialDesign:PackIcon Kind="EllipsisHorizontal" HorizontalAlignment="Right" />
                  </StackPanel>
                </materialDesign:Card>
              </Border>
            </WrapPanel>
            <materialDesign:Card Margin="30 20" UniformCornerRadius="20">
              <StackPanel>
                <Grid>
                  <TextBlock Margin="20" HorizontalAlignment="Left" FontWeight="SemiBold" Text="Instagram Subscribers" FontSize="18"/>
                  <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                    <TextBlock FontWeight="ExtraBold" FontSize="14" Text="&#xF06C;" FontFamily="wingdings" VerticalAlignment="Center" Foreground="#42A5F4" />
                    <TextBlock Text="Gained" HorizontalAlignment="Right" VerticalAlignment="Center" FontWeight="SemiBold" FontSize="14" Margin="5 0 10 0"/>
                    <TextBlock FontWeight="ExtraBold" FontSize="14" Text="&#xF06C;" FontFamily="wingdings" VerticalAlignment="Center" Foreground="#F55F54" />
                    <TextBlock Text="Lost" HorizontalAlignment="Right" VerticalAlignment="Center" FontWeight="SemiBold" FontSize="14" Margin="5 0 20 0" />
                  </StackPanel>
                </Grid>
                <lvc:CartesianChart Series="{Binding SeriesCollection}" Foreground="Black" Margin="10 0" Height="200">
                  <lvc:CartesianChart.AxisX>
                    <lvc:Axis Labels="{Binding Labels}" Separator="{x:Static lvc:DefaultAxes.CleanSeparator}" />
                  </lvc:CartesianChart.AxisX>
                  <lvc:CartesianChart.AxisY>  
                    <lvc:Axis LabelFormatter="{Binding Formatter}" />
                  </lvc:CartesianChart.AxisY>
                </lvc:CartesianChart>
              </StackPanel>              
            </materialDesign:Card>
            <WrapPanel HorizontalAlignment="Center">
              <materialDesign:Card Margin="10" UniformCornerRadius="20" Padding="10">
                <StackPanel>
                  <TextBlock Text="Key Matrics" Margin="10 20" FontWeight="SemiBold"/>
                  <Grid Height="150">
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition />
                      <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                      <RowDefinition />
                      <RowDefinition />
                      <RowDefinition />
                      <RowDefinition />
                    </Grid.RowDefinitions>
                    <TextBlock Text="Clicks" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <TextBlock Text="Links" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <TextBlock Text="Followers" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <TextBlock Text="Impressions" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="13" FontWeight="SemiBold" />
                    <StackPanel Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="#FFFFFF13" Background="#FFE8E8E8" BorderBrush="#FFF3F349" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>
                    <StackPanel Grid.Column="1" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="#FFFFFF13" Background="#FFE8E8E8" BorderBrush="#FFF3F349" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>
                    <StackPanel Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="SeaGreen" Background="#FFE8E8E8" BorderBrush="SeaGreen" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>
                    <StackPanel Grid.Column="1" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                      <TextBlock Text="10K" FontWeight="SemiBold" Margin="5 0" />
                      <ProgressBar Margin="5 0" Width="100" Height="8" Foreground="SeaGreen" Background="#FFE8E8E8" BorderBrush="SeaGreen" Value="78" />
                      <TextBlock Text="12K" FontWeight="SemiBold" />
                    </StackPanel>                    
                  </Grid>
                </StackPanel>
              </materialDesign:Card>
              <materialDesign:Card Margin="10" UniformCornerRadius="20" Background="#633648">
                <StackPanel Margin="10">
                  <TextBlock Text="Engagged Users" FontSize="14" Foreground="White" TextAlignment="Center" />
                  <TextBlock Text="12.5K" TextAlignment="Center" Margin="0 5" Foreground="White" FontSize="18" />
                  <lvc:CartesianChart Margin="0 5" Series="{Binding LastHourSeries}" Hoverable="False" DataTooltip="{x:Null}" Height="160" Width="160">
                    <lvc:CartesianChart.AxisX>
                      <lvc:Axis MinValue="0" />
                    </lvc:CartesianChart.AxisX>
                  </lvc:CartesianChart>
                  <materialDesign:PackIcon Kind="ArrowUp" HorizontalAlignment="Center" Margin="0 5" Width="20" Height="20" Foreground="#62A78B" />
                </StackPanel>
              </materialDesign:Card>
              <materialDesign:Card Margin="10" UniformCornerRadius="20" Background="#633648">
                <StackPanel Margin="10">
                  <TextBlock Text="Page Impression" FontSize="14" Foreground="White" TextAlignment="Center" />
                  <TextBlock Text="12.5K" TextAlignment="Center" Margin="0 5" Foreground="White" FontSize="18" />
                  <lvc:CartesianChart Margin="0 5" Series="{Binding LastHourSeries1}" Hoverable="False" DataTooltip="{x:Null}" Height="160" Width="160">
                    <lvc:CartesianChart.AxisX>
                      <lvc:Axis MinValue="0" />
                    </lvc:CartesianChart.AxisX>
                  </lvc:CartesianChart>
                  <materialDesign:PackIcon Kind="ArrowUp" HorizontalAlignment="Center" Margin="0 5" Width="20" Height="20" Foreground="#62A78B" />
                </StackPanel>
              </materialDesign:Card>
            </WrapPanel>
        </StackPanel>
      </Grid>
      <StackPanel Grid.Column="1" Background="White">
        <WrapPanel VerticalAlignment="Top" Margin="20 20 20 10">
          <Button Style="{StaticResource MaterialDesignFloatingActionButton}" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="Black">
            <StackPanel Margin="-5">
              <materialDesign:PackIcon Kind="BellOutline" />
            </StackPanel>
          </Button>
          <Button Background="#FFFFEEFA" BorderBrush="#FFFFEEFA" Foreground="#FFF0689E" Margin="10 0" Height="40">
            <WrapPanel HorizontalAlignment="Center" >
              <materialDesign:PackIcon Kind="GiftOutline" Width="25" Height="25" />
              <TextBlock Text="2 NEW UPDATES" VerticalAlignment="Center" FontWeight="SemiBold" Margin="10 0" />
            </WrapPanel>
          </Button>
          <Button Style="{StaticResource MaterialDesignFloatingActionButton}" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="Black">
            <StackPanel Margin="-5">
              <materialDesign:PackIcon Kind="BellOutline" />
            </StackPanel>
          </Button>
        </WrapPanel>
        <Border Margin="40 10" CornerRadius="20" Background="#FFFFFEFA">
          <Image Source="Images/aaa.jpg" Stretch="Uniform" x:Name="ImgCartoon" Height="150" />
        </Border>
        <Calendar Margin="45 10" />
        <materialDesign:Card Margin="20 10" Padding="5" UniformCornerRadius="20" HorizontalAlignment="Center">
          <WrapPanel Margin="10">
            <materialDesign:PackIcon Kind="HandPeace" Foreground="#FFC83D" VerticalAlignment="Center" Margin="10 0" />
            <TextBlock Margin="10 0" VerticalAlignment="Center">
              <TextBlock.Inlines>
                <Run Text="Say Hi To" />
                <Run Text="Laith Hart" FontWeight="SemiBold" FontSize="14" />
              </TextBlock.Inlines>
            </TextBlock>
            <Image Source="Images/bbb.jpg" Width="40" Height="40" x:Name="avatar1" Margin="10 0" />
          </WrapPanel>
        </materialDesign:Card>
        <materialDesign:Card Margin="20 10" Padding="5" UniformCornerRadius="20" HorizontalAlignment="Center">
          <WrapPanel Margin="10">
            <materialDesign:PackIcon Kind="HandPeace" Foreground="#FFC83D" VerticalAlignment="Center" Margin="10 0" />
            <TextBlock Margin="10 0" VerticalAlignment="Center">
              <TextBlock.Inlines>
                <Run Text="Say Hi To" />
                <Run Text="Laith Hart" FontWeight="SemiBold" FontSize="14" />
              </TextBlock.Inlines>
            </TextBlock>
            <Image Source="Images/bbb.jpg" Width="40" Height="40" x:Name="avatar2" Margin="10 0" />
          </WrapPanel>
        </materialDesign:Card>
      </StackPanel>
    </Grid>
</UserControl>

 

차트에 뿌려줄 데이터 및 동작을 cs파일에 구현합니다.

<Dashboard.xaml.cs>

using LiveCharts;
using LiveCharts.Wpf;
using System;
using System.IO;
using LiveCharts.Defaults;
using System.Windows.Controls;
using System.Windows.Media.Imaging;

namespace wpf_test04UT2
{

  public partial class Dashboard : UserControl
  {
    public SeriesCollection SeriesCollection { get; set; }
    public SeriesCollection LastHourSeries { get; set;  }
    public SeriesCollection LastHourSeries1 { get; set;  }
    public string[] Labels { get; set; }
    public Func<double,string> Formatter { get; set; }    
    public Dashboard()
    {
      InitializeComponent();
      SeriesCollection = new SeriesCollection{
        new StackedColumnSeries
        {
          Values = new ChartValues<double> {25, 52, 61, 89},
          StackMode = StackMode.Values,
          DataLabels = true
        },
        new StackedColumnSeries
        {
          Values = new ChartValues<double> {-15, -75, -16, -49},
          StackMode = StackMode.Values,
          DataLabels = true
        }
      };
      LastHourSeries = new SeriesCollection
      {
        new LineSeries
        {
          AreaLimit = -10,
          Values = new ChartValues<ObservableValue>
          {
            new ObservableValue(3),
            new ObservableValue(1),
            new ObservableValue(9),
            new ObservableValue(4),
            new ObservableValue(5),
            new ObservableValue(3),
            new ObservableValue(1),
            new ObservableValue(2),
            new ObservableValue(3),
            new ObservableValue(7),
          }
        }
      };
      LastHourSeries1 = new SeriesCollection
      {
        new LineSeries
        {
          AreaLimit = -10,
          Values = new ChartValues<ObservableValue>
          {
            new ObservableValue(13),
            new ObservableValue(11),
            new ObservableValue(9),
            new ObservableValue(14),
            new ObservableValue(5),
            new ObservableValue(3),
            new ObservableValue(1),
            new ObservableValue(2),
            new ObservableValue(3),
            new ObservableValue(7),
          }
        }
      };
      Labels = new[] { "Feb 7", "Feb8", "Feb 9", "Feb 10" };
      Formatter = GetValue => GetValue.ToString();
      DataContext = this;
      string imgCartoon = Directory.GetCurrentDirectory().ToString()+"\\Images\\aaa.jpg";      
      string imgavatar  = Directory.GetCurrentDirectory().ToString()+"\\Images\\bbb.jpg";   
      ImgCartoon.Source = new BitmapImage(new Uri(imgCartoon));
      avatar1.Source = new BitmapImage(new Uri(imgavatar));
      avatar2.Source = new BitmapImage(new Uri(imgavatar));
    }    
  }  
}

 

5. 결과

좀 있어보이나요? 좌측 메뉴가 동영상 강좌랑 달리 스타일이 안들어간 것 같습니다만, 수정하기 귀찮네요..필요할 때 하다보면 되겠죠..??ㅠㅠ

 

~~~끝~~~

반응형
반응형

오늘은 아래 유튜브 영상의 데스크탑 어플리케이션을 구현해보겠습니다.

https://www.youtube.com/watch?v=sgEhK3mbDYo

 

 

1. 라이브러리 설치

이번 영상에서는 Material Design과 LiveCharts를 사용합니다. 아래의 명령으로 Package를 설치해줍니다.

dotnet add package MaterialDesignThemes --version 4.2.1 // material Design 설치
dotnet add package LiveCharts.Wpf --version 0.9.7 // live chart 설치

또는 Nuget GUI Manager 를 설치 후

 

Shift + Ctrl + P 로 명령창에서 Nuget 입력 시 나타나는 명령을 수행합니다.

그리고 Nuget Package Manager에서 아래와 같이 설치해줍니다. Material Design Themes와 Livecharts.wpf로 검색되는 패키지를 설치해줍니다.


2. 라이브러리 적용

Material Design을 적용해야합니다. 적용하는 방법은 구글에서 < material design xaml >이라고 검색하면 나오는데, 여기 사이트를 참조하시면 되겠습니다. 그리고, 나중에 livechart에서 사용할 스타일도 정의해놓겠습니다.

<App.xaml>

<Application x:Class="wpf_test04UT1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wpf_test04UT1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

추가로, WS Simple Gallifreyan 폰트가 강좌 중간에 필요합니다. 적당히 다운받아 사용 가능한데, 이번엔 패스하겠습니다.

 

3. 구현

<MainWindow.xaml>

<Window x:Class="wpf_test04UT1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        xmlns:MetroChart="clr-namespace:De.TorstenMandelkow.MetroChart;assembly=De.TorstenMandelkow.MetroChart"
        xmlns:local="clr-namespace:wpf_test04UT1"
        mc:Ignorable="d"
        Title="MainWindow" Height="800" Width="1024"
        WindowStyle="None">
        
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid Grid.Column="1" Grid.Row="1" Background="#FFE6E6E6">
            <ScrollViewer>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="200"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                    </Grid.ColumnDefinitions>
                    
                    <Grid Grid.Column="0">
                        <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10">
                            <Rectangle.Effect>
                                <DropShadowEffect BlurRadius="20"/>
                            </Rectangle.Effect>
                        </Rectangle>
                        <Grid Margin="25" Height="120">
                            <Grid Width="35" Height="50" Background="#FFFFAF24" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
                                <Grid.Effect>
                                    <DropShadowEffect BlurRadius="20"/>
                                </Grid.Effect>
                                <materialDesign:PackIcon Kind="ContentCopy" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
                            </Grid>
                            <TextBlock Text="Espaco Usado" HorizontalAlignment="Right" FontFamily="Champagne &amp; Limousines" Margin="5" VerticalAlignment="Top" Foreground="Gray"/>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10 20">
                                <TextBlock Text="49/50" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Center" Foreground="Gray" FontSize="50"/>
                                <TextBlock Text="GB" FontFamily="Champagne &amp; Limousines" Margin="0 5" VerticalAlignment="Bottom" Foreground="Gray" FontSize="20" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20" Cursor="Hand">
                                <materialDesign:PackIcon Kind="AlertOutline" Foreground="Red" Width="10" Height="10" VerticalAlignment="Center" Margin="5 0"/>
                                <TextBlock Text="AAdquirir mais espaco" FontSize="10" Foreground="#FF8522BD"/>
                            </StackPanel>
                        </Grid>
                    </Grid>

                    <Grid Grid.Column="1">
                        <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10">
                            <Rectangle.Effect>
                                <DropShadowEffect BlurRadius="20"/>
                            </Rectangle.Effect>
                        </Rectangle>
                        <Grid Margin="25" Height="120">
                            <Grid Width="35" Height="50" Background="#FF41A43C" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
                                <Grid.Effect>
                                    <DropShadowEffect BlurRadius="20"/>
                                </Grid.Effect>
                                <materialDesign:PackIcon Kind="Store" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
                            </Grid>
                            <TextBlock Text="Receita" HorizontalAlignment="Right" FontFamily="Champagne &amp; Limousines" Margin="5" VerticalAlignment="Top" Foreground="Gray"/>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10 30">
                                <TextBlock Text="R$" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Margin="0 2" Foreground="Gray" FontSize="20"/>
                                <TextBlock Text="35.674,00" FontFamily="Champagne &amp; Limousines"  VerticalAlignment="Bottom" Foreground="Gray" FontSize="25" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20" Cursor="Hand">
                                <materialDesign:PackIcon Kind="Calendar" Foreground="Gray" Width="10" Height="10" VerticalAlignment="Center" Margin="5 0"/>
                                <TextBlock Text="Ultimas 24h" FontSize="10" Foreground="Gray"/>
                            </StackPanel>
                        </Grid>
                    </Grid>

                    <Grid Grid.Column="2">
                        <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10">
                            <Rectangle.Effect>
                                <DropShadowEffect BlurRadius="20"/>
                            </Rectangle.Effect>
                        </Rectangle>
                        <Grid Margin="25" Height="120">
                            <Grid Width="35" Height="50" Background="#FFCF1F1F" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
                                <Grid.Effect>
                                    <DropShadowEffect BlurRadius="20"/>
                                </Grid.Effect>
                                <materialDesign:PackIcon Kind="InformationOutline" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
                            </Grid>
                            <TextBlock Text="Erros Corrigidos" HorizontalAlignment="Right" FontFamily="Champagne &amp; Limousines" Margin="5" VerticalAlignment="Top" Foreground="Gray"/>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10 30">                                
                                <TextBlock Text="75" FontFamily="Champagne &amp; Limousines"  VerticalAlignment="Center" Foreground="Gray" FontSize="40" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20" Cursor="Hand">
                                <materialDesign:PackIcon Kind="Github" FontSize="15" Foreground="Gray" Width="10" Height="10" VerticalAlignment="Center" Margin="5 0"/>
                                <TextBlock Text="Monitorado pelo Git Hub" FontSize="11" Foreground="Gray"/>
                            </StackPanel>
                        </Grid>
                    </Grid>     

                    <Grid Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="3" HorizontalAlignment="Center" Width="580" Height="550"> 
                        <Grid Background="White" Margin="20 50 20 20">
                            <Grid.OpacityMask>
                                <VisualBrush Visual="{ Binding ElementName=BorderG1 }"/>
                            </Grid.OpacityMask>
                            <Border x:Name="BorderG1" CornerRadius="5" Background="White" />
                            <StackPanel VerticalAlignment="Bottom">
                                <TextBlock Text="Receita Diaria" FontFamily="Champagne &amp; Limousines" Margin="20 10" VerticalAlignment="Bottom" Foreground="Gray" FontSize="30"/>
                                <StackPanel Orientation="Horizontal" Margin="20 5" >
                                    <materialDesign:PackIcon Kind="ArrowUp" Foreground="Green" VerticalAlignment="Center"/>
                                    <TextBlock Text="55%" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Foreground="Green" FontSize="15"/>
                                    <TextBlock Text="Crescimento nas vendas hoje" Margin="20 0" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Foreground="Gray" FontSize="20"/>   
                                </StackPanel>
                                <StackPanel Orientation="Horizontal" Margin="10 5" >
                                    <materialDesign:PackIcon Kind="Clock" Foreground="Gray" VerticalAlignment="Center"/>                                    
                                    <TextBlock Text="Atualizado a 4 minutos" Margin="5 0" FontFamily="Champagne &amp; Limousines" VerticalAlignment="Bottom" Foreground="Gray" FontSize="20"/>   
                                </StackPanel>
                            </StackPanel>                            

                        </Grid>
                        <Grid Margin="50 20 50 200">
                            <Grid.OpacityMask>
                                <VisualBrush Visual="{ Binding ElementName=BorderG2 }"/>
                            </Grid.OpacityMask>
                            <Border x:Name="BorderG2" CornerRadius="15" Background="#FF340051" />

                            <MetroChart:RadialGaugeChart Background="{x:Null}" ChartTitle="Consumo" ChartSubTitle="" Foreground="LightGray" HorizontalAlignment="Center">
                                <MetroChart:RadialGaugeChart.Series>
                                    <MetroChart:ChartSeries
                                        DisplayMember="Titulo"
                                        ItemsSource="{Binding Path=Consumo}"
                                        SeriesTitle="Consumo"
                                        ValueMember="Porcentagem" />
                                </MetroChart:RadialGaugeChart.Series>
                            </MetroChart:RadialGaugeChart>
                        </Grid>                    
                    </Grid>               
                </Grid>
            </ScrollViewer>
        </Grid>

        <Grid Grid.Row="1">
            <Grid.Background>
                <LinearGradientBrush EndPoint="0 1" StartPoint="0 0">
                    <GradientStop Offset="0.0" Color="#aeaeae" />
                    <GradientStop Offset="1.0" Color="#888" />
                </LinearGradientBrush>
            </Grid.Background>
            <Grid.RowDefinitions>
                <RowDefinition Height="100"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.Effect>
                <DropShadowEffect BlurRadius="20"/>                
            </Grid.Effect>            

            <Grid Background="#ffa46fe4">
                <TextBlock Text="DASHBOARD" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="WS Simple Gallifreyan" Foreground="#FFBC96EA" FontSize="16"/>
            </Grid>

            <StackPanel Grid.Row="1">
            
                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="ViewDashboard" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="DASHBOARD"/>
                    </Grid>
                </Button>
                
                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="Account" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="PROFILE"/>
                    </Grid>
                </Button>

                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="ContentPaste" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="TABLES"/>
                    </Grid>
                </Button>

                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="TruckDelivery" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="PROVIDERS"/>
                    </Grid>
                </Button>

                <Button Margin="10" Background="#FF8522BD" BorderBrush="#FF8522BD">
                    <Grid Width="150">
                        <materialDesign:PackIcon Kind="Settings" VerticalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="CONFIGURATIONS"/>
                    </Grid>
                </Button>

            </StackPanel>
        </Grid>

        <Grid x:Name="GridBarraTitulo"  Grid.ColumnSpan="2" Background="#FF8522BD" MouseDown="GridBarraTitulo_MouseDown">
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Background="{x:Null}" Margin="10,0">
                <Button Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}" Width="25" Height="25" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White">
                    <materialDesign:PackIcon Kind="Bell"/>
                </Button>
                <Button Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}" Width="25" Height="25" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White">
                    <materialDesign:PackIcon Kind="Account"/>
                </Button>
                <Button x:Name="ButtonFecher" Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}" Width="25" Height="25" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" Click="ButtonFechar_Click">
                    <materialDesign:PackIcon Kind="Power"/>
                </Button>
            </StackPanel>
        </Grid>
    </Grid>
</Window>

 

<MainWindow.xaml.cs (데이터 주입부)>

using System.Windows;
using System.Collections.Generic;

namespace wpf_test04UT1
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Consumo consumo = new Consumo();
            DataContext = new ConsumoViewModel(consumo);
        }
        private void ButtonFechar_Click(object sender, RoutedEventArgs e){
            Application.Current.Shutdown();
        }
        private void GridBarraTitulo_MouseDown(object sender, RoutedEventArgs e){
            DragMove();
        }


    }
    internal class ConsumoViewModel{
        public List<Consumo> Consumo { get;  private set; }

        public ConsumoViewModel(Consumo consumo){
            Consumo = new List<Consumo>();
            Consumo.Add(consumo);
    }
    }

    internal class Consumo {
        public string Titulo { get; private set; }
        public int Porcentagem{ get; private set; }
        public Consumo(){
        Titulo = "Consum, Atual";
        Porcentagem = CalcularPorcentagem();

        }
        private int CalcularPorcentagem(){
            return 47; //
        }
  }
}

 

4. 결과

커맨드창에서 

dotnet build
dotnet run

하면 아래와 같이 이쁜 UI가 실행됩니다.

...이거 하느라...3시간 반 동영상보며 따라했네요..ㅠㅠ. 그래도 이쁜 결과물이 나와줘서 뿌듯합니다.

 

~~~끝~~~

반응형
반응형

VSCode에서 WPF 프로젝트를 하며 Material Design을 적용하는 방법을 알아보겠습니다.

 

1. Nuget Package Manager GUI 설치

우선 Nuget GUI Manager 를 설치해줍니다. 확작프로그램에서 nuget을 검색하여 설치합니다.

 

 

2. Material Design Theme설치

설치가 완료되면 Shift + Ctrl + P 로 명령창에서 Nuget 입력 시 나타나는 명령을 수행합니다. (한번만 수행하면 다음부터는 Shift +Ctrl + P만 눌러도 나타납니다.)

그러면 실행되는 Nuget Package Manager GUI에서 material design을 검색해서 설치해줍니다. 

   1) Install New Package 탭

   2) material design 검색

   3) 패키지 선택

   4) Install

참고) 다른 패키지들을 설치할 때, Dotnet Core와 호환되는 라이브러리인지 확인하려면 Open NuGet클릭하여 NuGet Gallary로 이동하여 확인하고 설치하시기 바랍니다.

 

3. Material Design Theme 적용

구글에서 "material design in xaml" 검색하여 해당 사이트로 이동한 후 적용방법을 확인/복사하여 적용해줍니다.

<화면 하단의 코드 복사>

복사

<App.xaml에 붙여넣기>

붙여넣기

<소스코드>

<?xml version="1.0" encoding="UTF-8"?>
<Application . . .>
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>

 

마지막으로 MainWindow.xaml파일에 Material Design 과 연결되는 부분을 한줄 붙여넣습니다. 이제 준비 끝.

 

4. Icon 적용 샘플 코드

<Window x:Class="wpf_test03.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:wpf_test03"
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <ResourceDictionary Source="/Resources/Styles.xaml"/>
    </Window.Resources>

    <StackPanel>
        <Grid>
            <materialDesign:Card Margin="10" UniformCornerRadius="15">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*" />
                        <ColumnDefinition Width="15*" />
                    </Grid.ColumnDefinitions>
                    <Grid.Resources>
                        <Style TargetType="materialDesign:PackIcon">
                            <Setter Property="Height" Value="30"></Setter>
                        </Style>
                    </Grid.Resources>
                    <Grid Grid.Column="0">
                        <ListView Margin="0 15">
                            <ListViewItem HorizontalAlignment="Center" Margin="0 10">
                                <Button Style="{StaticResource MaterialDesignFloatingActionButton}" HorizontalAlignment="Left"
                                BorderBrush="{x:Null}" Background="{x:Null}" Foreground="Black">
                                    <StackPanel Margin="-5">
                                        <materialDesign:PackIcon Kind="Resistor"/>
                                    </StackPanel>
                                </Button>
                            </ListViewItem>
                        </ListView>
                    </Grid>
                </Grid>
            </materialDesign:Card>
        </Grid>          
    </StackPanel>
</Window>

 

5. 결과

뭔가..트랜지스터...같은게 나오네요. 건승하시길 바랍니다.

 

~~~끝~~~

반응형

+ Recent posts