반응형

WPF 프로젝트를 연습해보다가 프로젝트를 개선할 수 있는 방법을 찾아서 정리하고자 합니다.

 

Window안에 UserControl을 선언해서 View-ViewModel간의 데이터를 전달하는 경우가 많았습니다.

 

특히, 여러 곳에서 호출되는 View-ViewModel은 다양한 초기 데이터를 받게됩나다.

 

기존에는 생성자 Overriding을 했었고, 일정 부분 코드가 중복되는 건 어쩔 수 없다고 생각했습니다.

 

그 때, 찾아낸 BASE에 대해 정리해봅니다.

 

 

기존 ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public ViewModelMain(string data1)
{
    Data1 = data1;
}
public ViewModelMain(string data1, string data2)
{
    Data1 = data1;
    Data2 = data2;
}
public ViewModelMain(string data1, string data2, string data3)
{
    Data1 = data1;
    Data2 = data2;
    Data3 = data3;
}

 

상속 ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public ViewModelMain(string data1)
{
    Data1 = data1;
}
 
public ViewModelMain(string data1, string data2) : this(data1)
{
    Data2 = data2;
}
 
public ViewModelMain(string data1, string data2, string data3) : this(data1, data2)
{
    Data3 = data3;
}

⭐ 초기화 로직의 중복을 줄일 수 있음

중복을 제거하여 수정 시, 유지보수성을 높임

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] View, ViewModel Singleton  (0) 2024.05.12
[WPF] 생성자 Overloading (2)  (0) 2024.05.11
[WPF] 한글 Encoding ANSI / UTF8  (0) 2024.04.22
[WPF] Static Resource와 Dynamic Resource  (0) 2024.04.20
[WPF] MaterialDesignTheme 적용  (0) 2024.04.13
반응형
 

대용량 데이터처리시 발생되는 UI Freeze 문제 해결 part1

과거의 경험한 내용 중에 대용량의 데이터를 파일이서 잃거나, Rest API를 통해서 전달 받아서, DataGrid나 ListBox에 출력시 UI Freeze 현상과 메모리 사용량이 증가하는 한다는 것을 해결해보려고 노력

kaki104.tistory.com

프로젝트를 하다가 대용량 데이터를 다운로드할 때, 가끔 UI가 멈추는 현상이 발생했습니다.

 

마침 이와 관련해서 연습해보면 좋은 글이 있어 실습을 진행하는데, 문제가 코드가 아닌 파일에서 발생했습니다.

 

글에서는 영어로 된 데이터를 사용하지만, 저는 마침 한글로 된 대용량 파일이 있어 사용을 했던 게 문제가 되었습니다.

 

인코딩이 제대로 되지 않아 한글이 나오지 않는 문제였습니다.

 

간단하게 파일 인코딩 형식 변환과 지정하는 방법을 다루고자 합니다.

 

 

* 파일 인코딩 변환방식 변경

1. .csv 파일을 메모장으로 열기

2. 다른 이름으로 저장에서 ANSI → UTF8로 Encoding 방식 변경

 

* C#코드에서 Encoding 타입 명시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using(var reader = new StreamReader(fileName, Encoding.UTF8))
{
    while (!reader.EndOfStream)
    {
        string line = reader.ReadLine();
        if(line != null)
        {
            DataModel model = GetDataModel(line);
            returnDatas.Add(model);
        }
    }
 
    reader.Close();
}

⭐ 중요한 점은 Encoding.Default를 사용할 경우, ANSI가 적용되어 한글이 깨져서 나옵니다.

UTF8을 직접 명시해줘야 합니다.

 

 

ANSI와 UTF8 차이

* ANSI

  * American National Standards Institute

  * 주로 영어 알파벳을 위한 ASCII 코드에 몇몇 추가 문자를 포함하는 인코딩 방식들

* UTF8

  * 8-bit Unicode Transformation Format

  * 유니코드를 사용하여 전 세계의 모든 문자를 포함할 수 있는 인코딩 방식

 

⭐ ANSI는 특정 지역의 문자 집합에 제한되어 있는 반면, UTF-8은 전 세계의 모든 문자를 지원

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] 생성자 Overloading (2)  (0) 2024.05.11
[WPF] 생성자 Overloading  (1) 2024.04.27
[WPF] Static Resource와 Dynamic Resource  (0) 2024.04.20
[WPF] MaterialDesignTheme 적용  (0) 2024.04.13
[WPF] WebView2와 동영상  (0) 2024.04.13
반응형

WPF를 학습하며 헷갈렸던 부분을 정리해두었습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022

- Framework: .NET 8.0


WPF에서 Resource는 크게 2가지가 있습니다.

Static Resource와 Dynamic Resource

 

저는 주로 ResourceDictionary를 사용하면 Window에서 Dictionary를 선언하고 Static으로 사용합니다.

그런데 이번에 토글버튼을 통해 테마를 변경해보며 DynamicResource를 사용하게 되어 간단하게 차이점을 정리해보고자 합니다.

 

StaticResource

 *  컴파일 시 리소스 바인딩

 * 즉, 애플리케이션이 로드될 때 한 번 리소스를 찾아서 적용하고, 그 이후에는 리소스의 변경을 반영하지 않음

 * 성능 측면에서 실행 시에 리소스를 찾기위한 추가적인 계산이나 검색을 수행할 필요가 없어 DynamicResource보다 효율적

 

DynamicResource

 * 실행 시간에 리소스를 찾아 바인딩

 * 리소스 참조가 실행 시간에 이루어지기 때문에, 참조하는 리소스가 초기에는 없다가 나중에 추가 가능

 

따라서, 리소스가 변경될 일이 없고 성능이 중요할 경우에는 Static을

리소스가 변경될 가능성이 있거나 로드 시에는 리소스가 없으나 실행 중 리소스가 생길 경우에는 Dynamic을 사용

 

✍️ 예시

View

1
2
3
4
5
6
7
8
9
10
11
12
13
<Window x:Class="SwitchThemes.MainWindow">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Styles/DictionaryMainStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
 
    <Grid Background="{DynamicResource backgroundBlack}">
        <!-- 생략 -->
    </Grid>
</Window>

 

ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void ChangeTheme()
{
    if (IsLightMode)
    {
        AppTheme.ChangeTheme(new Uri("/Styles/DictionaryThemeWhite.xaml", UriKind.Relative));
        ThemeMode = "Light";
        return;
    }
 
    if (!IsLightMode)
    {
        AppTheme.ChangeTheme(new Uri("/Styles/DictionaryThemeBlack.xaml", UriKind.Relative));
        ThemeMode = "Dark";
        return;
    }
}

 

⭐ Grid의 Backgound 속성이 다음과 같이 Checked 여부에 따라 변경되는 경우라면, StaticResource가 아닌 Dynamic Resource를 사용해야 함

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] 생성자 Overloading  (1) 2024.04.27
[WPF] 한글 Encoding ANSI / UTF8  (0) 2024.04.22
[WPF] MaterialDesignTheme 적용  (0) 2024.04.13
[WPF] WebView2와 동영상  (0) 2024.04.13
[WPF] Button 클릭 영역과 Background  (0) 2024.04.06
반응형

QR Code 생성 프로그램을 만들면서 헤맸던 부분을 정리해두었습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022

- Framework: .NET 8.0


1. MaterialDesignTheme 버전

버전이 5.0.0부터 App.xaml에 작성해야하는 코드가 변경되었습니다.

 

공식문서가 거짓말을 하고 있기때문에, Github으로 이동합니다.

 

Material Design In XAML Toolkit

Material Design for WPF and the Windows Desktop

materialdesigninxaml.net

 

 

Getting Started

Google's Material Design in XAML & WPF, for C# & VB.Net. - MaterialDesignInXAML/MaterialDesignInXamlToolkit

github.com

 

중요한 건, 공식문서를 다음과 같이 변경해서 사용해야 한다는 것입니다.

1
2
3
4
5
6
7
8
9
10
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Secondary/MaterialDesignColor.Lime.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

 

 

2. 기본 Style 상속

PackIcon을 추가하니, Hover할 때 클릭할 때 예쁜 애니메이션이 추가되어있었습니다.

근데, 색깔을 바꾸고 싶습니다.

 

용기있게 ListView의 ItemContainer Style을 선언하면, 기본으로 적용한 모든 기능을 잃게 됩니다..☠️

 

그럴 때 xaml에서 사용할 수 있는 style 상속 기능 BaseOn을 사용하면 됩니다🤓.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<ListView VerticalAlignment="Top" 
          Margin="0 70"
          ItemsSource="{Binding MenuModels}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="#DCBFFF"/>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#DCBFFF"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Margin="20 0" Orientation="Horizontal">
                <materialDesign:PackIcon Kind="{Binding Icon}" Width="30" Height="30"/>
                <TextBlock Text="{Binding Title}" 
                           VerticalAlignment="Center" 
                           Margin="10 0" 
                           FontSize="18"
                           Foreground="#FFFFFF"/>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

 

 

 

🎇 결과물

 

 

 

📚 참고 자료

 

WPF overriding ListViewItem style when use Material Design In XAML Toolkit

I installed Material Design In XAML Toolkit to my project. I have ListView which contains within itself GridView (with GridViewColumns) and i want to override styles for each row in this table. But...

stackoverflow.com

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] 한글 Encoding ANSI / UTF8  (0) 2024.04.22
[WPF] Static Resource와 Dynamic Resource  (0) 2024.04.20
[WPF] WebView2와 동영상  (0) 2024.04.13
[WPF] Button 클릭 영역과 Background  (0) 2024.04.06
[WPF] MVVM Scroll 동작 구현  (0) 2024.03.31
반응형

최근에 프로젝트를 진행하면서 동영상을 프로그램에서 재생하며 어려웠던 부분을 정리하였습니다.

 

👉 기본 환경

- Language: C#, xaml

- IDE: Visual Basic 2022

- Framework: .NET 8.0


📹동영상..

저에게 주어진 임무는 유튭.. 동영상을 프로그램에서 재생하라..!

 

Web할 때 동영상 재생.. 유튭 태그만 적어주면 끝났던 희미한 기억만 남았는데,

☠️ WPF에서는 패키지도 설치해야하고..

☠️ 컨트롤도 마음처럼 안되고..

☠️ 게시 후에 권한 문제도 생기고..

기억에 확실히 남겨두자는 마음으로.. 기록해봅니다✍️.

 

🚨 1. 동영상 재생에 필요한 태그 찾기

제가 찾아본 태그는 크게 3가지 였습니다.

 * (내장) WebBrowser

 * (Nuget, Google) CefSharp.wpf

 * (Nuget, MS) WebView2

 

Nuget 패키지 설치는 프로그램 용량이 커질 수 있기 때문에 최대한 지양했습니다.

그래서 첫 번째로 WebBrowser를 사용했는데, Script Error 문제로 하루동안 찾아보다가 포기했습니다.

 

그 다음 두 번째로는 CefSharp.wpf를 사용했습니다.

왜냐면 Google에서 WPF youtube 재생을 검색해보니, CefSharp.wpf를 사용하는 방법이 첫 번째로 나왔기 때문입니다.

그러나, 개인적으로 노트북에서 먼저 시도를 했을 때,

Warning	NU1701 Package 'CefSharp.Wpf 122.1.120' was restored 
using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, 
.NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, 
.NETFramework,Version=v4.8, .NETFramework,Version=v4.8.1' 
instead of the project target framework 'net8.0-windows7.0'. 
This package may not be fully compatible with your project.

위와 같은 오류가 발생해서 포기했습니다.

 

그래서 마지막 종착지, 사이좋게 MS에 MS package를 붙여주기로 결정했습니다.

 

2. Nuget 설치 및 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Window x:Class="WebViewTest.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:WebViewTest"
        xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
        mc:Ignorable="d"
        Title="WebViewTest" Height="450" Width="800"
        Name="WebViewTest"
        >
    <Grid>
        <wv2:WebView2 x:Name="webView"
                      Source="https://www.youtube.com/embed/1Qtr8TznwNI"
                      />
    </Grid>
</Window>

 

Window 태그에 wv2를 추가하고 재생할 주소를 Source에 입력해줍니다.

 

저는 Embed 타입을 사용할 예정이라서 youtube에 embed 경로를 입력해주었습니다.

 * embed경로: www.youtube.com/embed/동영상ID

 

연습할 때는 하드코딩으로 작성했지만, MVVM이면 Source 부분을 바인딩하시면 됩니다.

 

 

🚨 3. 전체화면 컨트롤

유튜브 재생은 되는데, 전체화면을 누르면.. 

 * 윈도우보다 큰 창으로 WebView 크기를 조절할 수 없고,

 * 유튜브가 은밀하게 전체화면을 제공할 수 없다고 하는데,

  고객센터에 들어가보니 수줍게 ' YouTube가 아닌 웹사이트에서 YouTube 동영상을 시청하는 경우 전체 화면 옵션이 제공되지 않을 수 있습니다.'라고 합니다.

 

그래서 대안이 크게 2가지가 나왔는데,

  3.1. 윈도우를 전체 화면으로 같이 만들자

  3.2. 전체화면 클릭 시, 웹브라우저를 실행하자

 

저는 윈도우를 전체 화면으로 만드는 방법을 선택했는데, 같은 메서드를 사용할 예정이라 변환이 쉽습니다.

마음에 드시는 걸로 선택해서 사용하시면 됩니다.

 

제가 생각했을 때의 각각의 장단점은 다음과 같습니다.

 * 윈도우 전체화면 시,

  * 장: 간편

  * 단: 전체 화면을 제공할 수 없다는 안내 문구 발생

        : 창과 웹뷰의 크기를 즉각적으로 연동하기 어려움

 

* 웹브라우저 실행 시,

 * 장: 전체 화면 가능, 유튜브에서 제공하는 기본 옵션들 자유롭게 사용 가능

 * 단: 웹으로 전체화면 실행 시, 처음부터 다시 재생

 (코드를 통해서 넘기는 방법이 있는 것 같지만, 너무 복잡합니다.)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
namespace WebViewTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            InitializeAsync();
        }
 
        /// <summary>
        /// WebView2 컨트롤을 초기화하고, 
        /// 특정 이벤트를 구독하는 과정을 비동기적으로 처리하는 메서드
        /// </summary>
        private async void InitializeAsync()
        {
            await webView.EnsureCoreWebView2Async();
            // CoreWebView2 환경을 초기화
            // 메서드가 성공적으로 반환되면 CoreWebView2 객체가 준비된 상태임을 보장
            webView.CoreWebView2.ContainsFullScreenElementChanged += CoreWebView2_ContainsFullScreenElementChanged;
            // ContainsFullScreenElementChanged
            // 웹 페이지 내에서 전체 화면 요소(예: 비디오의 전체 화면 재생)의 상태가 변경될 때마다 발생
        }
 
        /// <summary>
        /// 웹 페이지 내의 요소가 전체 화면 모드로 전환될 때마다 이 이벤트가 발생
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CoreWebView2_ContainsFullScreenElementChanged(object sender, object e)
        {
            var isFullScreen = webView.CoreWebView2.ContainsFullScreenElement;
            Application.Current.Dispatcher.Invoke(() =>
            {
                if (isFullScreen)
                {
                    // Enter full-screen mode
                    this.WindowStyle = WindowStyle.None;
                    this.WindowState = WindowState.Maximized;
                    this.ResizeMode = ResizeMode.NoResize;
                    webView.Width = this.ActualWidth;
                    webView.Height = this.ActualHeight;
                }
                else
                {
                    // Return to normal mode
                    this.WindowStyle = WindowStyle.SingleBorderWindow;
                    this.WindowState = WindowState.Normal;
                    this.ResizeMode = ResizeMode.CanResize;
                    webView.Width = this.ActualWidth;
                    webView.Height = this.ActualHeight - 35;
                }
            });
        }
 
    }
}

 

ContainsFullScreenElementChanged 이벤트를 통해서 전체화면을 처리하였습니다.

 

WebView2에서 제공하는 기본 컨트롤은 다음 공식문서를 참고하면 됩니다.

 

CoreWebView2 Class (Microsoft.Web.WebView2.Core)

WebView2 enables you to host web content using the latest Microsoft Edge browser and web technology.

learn.microsoft.com

 

만일 전체화면 클릭 시, 웹으로 이동하는 것을 구현하고 싶으시다면 ContainsFullScreenElementChanged에 선언하면 됩니다.

 

🚨 4. 게시 후, 주의 사항

(게시하는 방법 참조)

게시를 할 때 위치 및 게시 후 프로그램 설치 위치 모두 권한 문제에 유의해야 합니다.

 

WebVIew2 폴더 권한 문제

안녕하세요. 윈폼으로 웹뷰2를 사용하여 응용 프로그램을 만들어서 배포하였습니다. (관리자 권한 적용) 해당 프로그램은 Program Files 폴더 하위에 프로젝트명으로 되어 있습니다. 그런데 어떤 PC

forum.dotnetdev.kr

위치를 ProgramFiles로 설정할 경우, 접근 권한의 문제가 생기기 때문에 ProgramData 등 상대적으로 권한이 낮은 다른 곳에 설치를 할 수 있습니다.

 

 

 

😮 오늘의 깨달음: 폴더마다 접근 권한이 다르고, 웹에서 로컬 폴더로의 직접 접근은 보안상 이유로 제한된다.

 

반응형

'C# > WPF' 카테고리의 다른 글

[WPF] Static Resource와 Dynamic Resource  (0) 2024.04.20
[WPF] MaterialDesignTheme 적용  (0) 2024.04.13
[WPF] Button 클릭 영역과 Background  (0) 2024.04.06
[WPF] MVVM Scroll 동작 구현  (0) 2024.03.31
[WPF] ListView와 SelectedItem 초기화  (0) 2024.03.31