wpf2023. 6. 9. 18:37

 private void MessageCheck_Checked(object sender, RoutedEventArgs e)
        {
            if (IsLoaded == false)
                return;

            var name = (sender as ToggleButton).Name;

            var ctl = xGroups.FindName(name) as ToggleButton;

            DataManager.LocalData.MessageSelect.GetType().GetProperty(name.Remove(0, 1)).SetValue(DataManager.LocalData.MessageSelect, ctl.IsChecked);

            DataManager.Instance.SaveData();
        }

        private void TelegramMessageSelectPage_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((e.NewValue) as bool? == false)
                return;

            foreach (var item in DataManager.LocalData.MessageSelect.GetType().GetProperties())
            {
                var ctl = xGroups.FindName($"x{item.Name}") as ToggleButton;

                if (ctl != null)
                    ctl.IsChecked = (bool)item.GetValue(DataManager.LocalData.MessageSelect);
            }
        }

 

 public class MessageSelectModel
    {
        public bool IsDeepSleep { get; set; }

        public bool IsStartEndMap { get; set; }

        public bool IsDriveEnd { get; set; }
    }

 

 

 

그냥 바인딩하는게 최고지만 피지 못할경우에는 

 xIsAutoAfterBlowBtn.IsChecked = DataManager.LocalData.IsAutoAfterBlow; <-이런식으로 노가다 작업하지말고

 

xName이랑 프로퍼티랑 이름을 같게해서 반복작업을 줄여보자

Posted by 동동(이재동)
wpf2023. 6. 8. 14:50

https://blog.powerumc.kr/189

 

[MEF] 1. Managed Extensibility Framework 이란?

MEF (Managed Extensibility Framework) 란? Menaged Extension Framewkr(이하 MEF) 란? 가장 쉽게 얘기하자면, 어플리케이션과 컴포넌트의 재사용성을 높일 수 있는 프레임워크입니다. 기존의 어플리케이션은 하나

blog.powerumc.kr

 

여기에 잘정리 되어 있으니 보자..

 

Menaged Extension Framewkr(이하 MEF) 란? 가장 쉽게 얘기하자면, 어플리케이션과 컴포넌트의 재사용성을 높일 수 있는 프레임워크입니다. 기존의 어플리케이션은 하나의 목적을 하나의 어플리케이션으로 구현한 정적인(Statically) 어플리케이션이라면, MEF 는 보다 동적인(Dynamically) 어플리케이션을 구축할 수 있는 새로운 라이브러리를 제공합니다.

Posted by 동동(이재동)
wpf2023. 6. 7. 15:25

서버야 프로젝트 템플릿이 있어서 그냥 자동으로 만들어지지만

WPF client에서 Protos에 greet.proto를 복사하고 따라했지만 빌드에러가 났다..

 

구글 검색후 해결했다

 

https://stackoverflow.com/questions/60810497/grpc-erros-in-wpf-net-core

 

gRPC erros in WPF .NET Core

I want to create a simple WPF Core, gRPC project. This "code" works perfectly in my .NET Core Console app, however WPF seems to be something special. Proto File syntax = "proto3"...

stackoverflow.com

 

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWPF>true</UseWPF>
    <CoreCompileDependsOn>$(CoreCompileDependsOn);Protobuf_Compile</CoreCompileDependsOn>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.23.2" />
    <PackageReference Include="Grpc.Net.Client" Version="2.53.0" />
    <PackageReference Include="Grpc.Tools" Version="2.54.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
    
  </ItemGroup>

</Project>

 

프로젝트 편집에서

 

<CoreCompileDependsOn>$(CoreCompileDependsOn);Protobuf_Compile</CoreCompileDependsOn>

이걸 추가함으로써 빌드가 되었다.

 

 

'wpf' 카테고리의 다른 글

[WPF] 체크박스 xName을 이용하여 반복작업 하지 않고 간결하게  (0) 2023.06.09
MEF란?  (0) 2023.06.08
dynamic property 에서 Set을 할떄  (0) 2022.12.05
public (string name, int age) GetUser()  (0) 2022.10.26
PeriodicTimer  (0) 2022.08.31
Posted by 동동(이재동)
wpf2022. 12. 5. 11:44

await SendConfirmMsg(msgSplit, DataManager.LocalData.LongTrendBuy, "QuitRange");

 

 

 

private static async Task SendConfirmMsg(string[] msgSplit, dynamic data, string prop)
        {
            double numValue;
            bool isNum = double.TryParse(msgSplit[2], out numValue);

            data.GetType().GetProperty(prop).SetValue(data, numValue, null);           

            DataManager.Instance.SaveData();
            await TelegramPushService.SendMessage($"{msgSplit[0]} {msgSplit[1]} {numValue}");
        }

 

 

이런식으로 반복되는 구문을 dynamic을 이용해서 짧게 만들수 있다.

 

중요

 

data.GetType().GetProperty(prop).SetValue(data, numValue, null);   

 

참고

https://stackoverflow.com/questions/12970353/c-sharp-dynamically-set-property

'wpf' 카테고리의 다른 글

MEF란?  (0) 2023.06.08
[WPF] gRPC Client 빌드 안될때 대처법  (0) 2023.06.07
public (string name, int age) GetUser()  (0) 2022.10.26
PeriodicTimer  (0) 2022.08.31
2개의 LIST 비교 하는것  (0) 2021.11.18
Posted by 동동(이재동)
wpf2021. 11. 18. 18:01

private bool IsDiffList<T>(List<T> list1, List<T> list2)
        {
            var diff1 = list1.Except(list2);
            var diff2 = list2.Except(list1);

            var resultDiff = diff1.Concat(diff2).ToList();

            if (resultDiff.Count > 0)
                return true;
            else
                return false;
        }

 

if (IsDiffList<OrderInfo>((xProfitOrderListbox.ItemsSource as List<OrderInfo>).ToList(), _service.OrderInfoList))
                {
                    xProfitOrderListbox.ItemsSource = _service.OrderInfoList;
                    xProfitOrderListbox.Items.Refresh();
                }

 

이런식으로 반복적으로 item을 넣어야 하는곳에 넣어준다. timer를 이용하면 객체를 계속 생성하기때문에

 

무조건 넣어주면 메모리 Leak 이 걸린다. 그렇기 떄문에 변경될때만 적용되게 해야한다.

'wpf' 카테고리의 다른 글

public (string name, int age) GetUser()  (0) 2022.10.26
PeriodicTimer  (0) 2022.08.31
싱글톤 쓰기  (0) 2021.08.24
Combox 에 Enum 바인딩  (0) 2021.05.06
WPF에서 기본적으로 제공해주는 BoolToVisConverter 컨버터  (0) 2020.04.28
Posted by 동동(이재동)
wpf2020. 3. 6. 17:53

WPF에서 텝이 변결될 때 발생하는 이벤트 키워드인 SelectionChanged를 TabControl에 사용해서 탭을 가져오는 형태로 코드구성을 진행하는 중 이상한 점이 발견됬다.

내가 만드는 프로그램에서는 2번째 탭을 클릭하면 SelectionChanged가 호출 되고 2번째 탭 내의 ListBox 컨텐츠가 업데이트 되는 형식으로 코드가 진행될 것으로 예상하고 디버그를 하였으나, 실제로는 2번째 탭을 클릭하면 SelectionChanged가 재귀적으로 무한호출 되버리는 문제가 발생되었다.

문제는 TabControl 내부에 컨텐츠가 업데이트 되거나 무슨 변화가 존재할 경우에도 해당 이벤트가 호출된다는 점이다. 이럴 대는 Source 값이 TabControl인지 비교하는 항목이 추가되야 하며 아래와 같은 코드구성이 가능하다.

private void MainTabChanged(object sender, SelectionChangedEventArgs e)
{
int tabItem = ((sender as TabControl)).SelectedIndex;
if (e.Source is TabControl) // This is a soultion of those problem.
{
switch (tabItem)
{
case 0: // Chatting
Debug.WriteLine("Tab: Chatting");
if (MainChatList.Items.Count > 0)
{
MainChatList.SelectedIndex = MainChatList.Items.Count - 1;
MainChatList.ScrollIntoView(MainChatList.Items[MainChatList.Items.Count - 1]);
}
break;
case 1: // Users
Debug.WriteLine("Tab: Users");
break;
case 2: // Friends
Debug.WriteLine("Tab: Friends");
this.OnFriendTabActive();
break;
default:
Debug.WriteLine("Tab: " + tabItem);
break;
}
}
}

 

소스의 4번째 줄을 확인하면 TabControl의 문제점을 개선하는 코드를 확인 할 수 있다.

 

 

if (e.Source is TabControl)<--로 확인가능

Posted by 동동(이재동)
wpf2019. 3. 21. 17:44

List를 그대로 대입시켜버리면 해당 객체가 바뀌기때문에


clone, deep copy를 해야한다.


List<Book> books_2 = books_1.ConvertAll(book => new Book());



내가 봤을때는 이게 가장 나은 방법같다.

https://stackoverflow.com/questions/14007405/how-create-a-new-deep-copy-clone-of-a-listt

Posted by 동동(이재동)
wpf2019. 2. 26. 16:56

얼굴 인식 2번쨰

Face API를 항상 호출하면 1분에 20번(무료 버전 기준) 호출 제한을 넘기때문에

일단 openCV 에서 얼굴을 최대한 감지한후 호출을 해야 호출 제한에 어느정도 자유롭다.

일단 openCVSharp을 설치하면

CascadeClassifier class의 DetactMultiScale을 이용해서 사람 얼굴을 감지할수 있다.

private readonly CascadeClassifier _localFaceDetector = new CascadeClassifier();
_localFaceDetector.Load("Data/haarcascade_frontalface_alt.xml");

_grabber.NewFrameProvided += (s, e) =>
{
var rects = _localFaceDetector.DetectMultiScale(e.Frame.Image, 1.3, 1, 0, new OpenCvSharp.Size(200, 200));
.
.
//Face API를 이용해서 얼굴 찾기

이런식으로 1차적으로 openCV 얼굴 검출 2차 Face API를 이용해서 얼굴 찾기 하면 된다.

프레임별로 얼굴을 찾는 부분을 호출 하기 때문에 2초 정도 안에는 다시 FaceAPI를 호출하지 못하도록 구현해야한다.


DetectMultiScale을 이용해서 검출할수 있는 최대 인원 및 최소 사이즈를 설정할수 있다. 샘플에서는 얼굴 크기가 200 이상인사람만 찾도록 구현했다.

샘플은 웹캠이 구동되고 얼굴을 비추면 첨보는 사람면 등록을 , 등록된 사람이면 userData의 이름 및 성별등등을 출력해준다. Face API는 최대한 호출되지 않도록 openCV에서 얼굴이 완전히 검출 되었을때만 사용했다.


FaceApiTest2.zip













Posted by 동동(이재동)
wpf2017. 9. 12. 12:40

listview
1
2
3
4
5
6
7
8
9
10
11
12
                <ListView.ItemContainerStyle>
                    <Style TargetType="{x:Type ListViewItem}">
                        <Setter Property="Background" Value="Transparent" />
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ListViewItem}">
                                    <ContentPresenter />
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ListView.ItemContainerStyle>


button


1
2
3
4
5
6
7
8
9
10
11
12
13
14
 <Button.Style>
                <Style TargetType="{x:Type Button}">
                    <Setter Property="Background" Value="Transparent"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type Button}">
                                <Border Background="{TemplateBinding Background}">
                                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
</Button.Style>


Posted by 동동(이재동)
wpf2017. 9. 6. 12:13

예를 들면 3이라는 숫자가 바인딩 되어 있고

이걸 3개월로 바꾸고 싶으면 Converter를 쓰면 되지만 일일이 만들기가 엄청 귀찮다


 <TextBlock Text="{Binding Month, StringFormat={}{0}개월}"/>


돈도 

<TextBlock Text="{Binding Money,StringFormat='##,#'}" />


이렇게 하면 300,000 형식으로 나온다.



Posted by 동동(이재동)
wpf2017. 8. 8. 16:18

예를들어 View의 UserControl의 DataContext에 데이터를 주입하고

 <local:CardCancelControl DataContext="{Binding CardCancelData}" />


이런식으로...

유저컨트롤에서 버튼 커맨드를 넣었을때


 <Button Content="확인" Command="{Binding DataContext.CardCancelCommand}"  CommandParameter="Cancel" />


이런식으로 넣으면 안된다. datacontext안에 서 command를 호출하기 때문이다


이렇게 할려면 상위에서 DataContext를 빼야 작동한다.


그러면 상위에서 호출되게 할려면 어떻게 해야할까.


 <Button Content="확인" Command="{Binding Path=DataContext.CardCancelCommand,

                        RelativeSource={RelativeSource Mode=FindAncestor,

                        AncestorType={x:Type local:PopupControl}}}" CommandParameter="Cancel" />


이렇게 하면 된다.

참고 : https://stackoverflow.com/questions/3404707/access-parent-datacontext-from-datatemplate


Posted by 동동(이재동)
wpf2017. 8. 7. 11:29

일반적으로 Grid라든지 컨트롤들은 자동으로 해상도에 맞게 조절해주지만


이미지는 크기가 정해져 있어서 이미지 크기가 유동적으로 변하지 않는다.


그래서 만약 Grid를 사용할때 퍼센트를 이용해서 분할하였다면 이미지를 사용한 Row나 column은 이미지가 짤릴경우가 있다.


이럴때는 ViewBox로 그 Row를 감싸면 깔끔해진다.



Posted by 동동(이재동)
wpf2017. 7. 17. 16:58

Grid 같은 패널에 Add,Clear 하면서 임시로 nagiation처럼 되도록 하는 방법이 있지만


Frame을 이용하면 더 깔끔하게 가능하다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public static class NavigationManager
    {
        private static Frame _mainContentFrame;
 
        public static void SetFrame(Frame frame)
        {
            _mainContentFrame = frame;
        }
 
        public static void Navigate(UserControl page)
        {
            _mainContentFrame.Navigate(page);
        }
    }


Xaml


1
2
3
<Grid x:Name="xMainWindowPanel">
        <Frame x:Name="xMainFrame" NavigationUIVisibility="Hidden" />
</Grid>


사용법


1
2
3
4
5
  private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            NavigationManager.SetFrame(xMainFrame);
            xMainFrame.Navigate(new LoginPage());
        }

추가...

naviagte를 하게 되면 이전 페이지가 필요 있으면 메모리에 남게 되므로 메모리 관리에 문제가 있을수 있다.

 public static void Navigate(UserControl page)
        {
            _mainContentFrame.Navigate(page);

            while (_mainContentFrame.CanGoBack == true)
            {
                _mainContentFrame.RemoveBackEntry();
            }
        }

RemoveBackEntry()로 지워주자


Posted by 동동(이재동)
Surface2011. 5. 27. 11:06

WPF에서 이런식으로 스토리를 보여주고 싶었다.(이건 완성된버전 ㅋㅋ)

 

image

 

이건 그냥 TextBlock으로 되는것이 아니다.

 

그래서 FlowDocument를 사용하였다..

 

일단 xaml에서 이렇게 코딩을 했다.

 

<FlowDocumentScrollViewer Grid.Row="1" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Hidden" >
    <FlowDocument Background="Transparent">                                        
        <Paragraph FontFamily="Bell MT" FontSize="24" x:Name="DescriptionParagraph">
            <Floater Width="500"  HorizontalAlignment="Left">                            
                <BlockUIContainer>
                    <Rectangle Height="250" />
                </BlockUIContainer>
            </Floater>
            One Day, most of the town’s roads are ruined by the heavy rain. On that day, school bus-Schoobi happens to be late because of constructions on the road. Worrying that children may be waiting at the bus stop, Schoobi drives through the traffic with full speed, even though other cars are starring at him in a disapproving manner. Schoobi gets to a costal road, however, the road condition there is also messy. Dilly-dallying and regreting to go back. Schoobi ends up ramming into the guardail. Schoobi is now in the danger of falling down the cliff. Can Robocar Poli and his team save Schoobi?
        </Paragraph>
    
    </FlowDocument>
   
</FlowDocumentScrollViewer>
 
보면 알겠지만 FlowDocument에서 Paragraph를 사용하고 안에 Floater를 이용해서 안에 투명한 사각형을 왼쪽에 정렬하고 바깥쪽에 글을 입력하였다.
 
그럼 이제 안에 내용 Text를 계속 유동적으로 바꿔야 한다.
그럼 어떻게 해야할까? behind에서 수정하면 된다.
 
paragrah의 x:name을 DescriptionParagraph를 정의 했으니 이걸 변경하면 된다. 소스를 보자
 
private void SetDescriptionPlaceholder(string param)
        {
            DescriptionParagraph.Inlines.Remove(DescriptionParagraph.Inlines.Where(c => c is System.Windows.Documents.Run == true).Select(c => c).FirstOrDefault());
            DescriptionParagraph.Inlines.Add(param);
        }
 

이렇게 inline을 삭제하고 다시 추가하는 형식으로 바꾸었다.

 

이렇게 하면 끝~

Posted by 동동(이재동)
Surface2011. 5. 19. 16:06

아 이것때문에 시간 아까운데 2시간이나 까먹었다…

 

실버라이트랑 다르게 이상하게

 

Blend로 VisualState를 만들고

 

VisualStateManager.GoToState(this, "Title", true);

 

이렇게 state간의 전환을 할려고 했으나 계속 false를 return 했다. ㅡ.ㅡ!!!

 

인터넷 찾아보니…

 

WPF 버그라던데…

 

해결법은

 

VisualStateManager.GoToElementState(this.Content as FrameworkElement, "Title", true);

 

이렇게 element단위에서 해야한다.. 내참 인터넷에 왜 이런거 해결하는 법 하나도 없는거야?

Posted by 동동(이재동)
VisualStudio2009. 1. 15. 15:03
F12 : 내가 젤 많이 쓴다.... 메소드 찾아가기 ㅋㅋ 

Ctrl+k,k : bookmark기능 ,해제

Ctrl+k,n,p : bookmark 찾아가는데 n은 다음 p 는 이전

F5 : debuging 모드 실행이므로 실행이 느리다

ctrl+f5: 릴리즈모드

F9: 그냥 마우스 더블클릭이 더편해서 잘안씀 break point

ctrl+shift+F9 : 모든 break point 해제

ctr+R,M : 메소드 만들기..... 만들 소스 드래그후 만들면 편하다.

alt+shift+F12 : 아주 좋은 기능이다 모든 프로젝트에서 찾는데 마치 acroedit의 file에서 찾기 기능과 유사하다.
                    근데 shift+f12로도 되는거 같다 이게 더 편한듯?

ctrl+i : ctrl+f도 좋지만 자동완성처럼 오페라나 크롬 파폭처럼 한글자씩 찾을때 유용하다..
 
blend에서 창 다 지우는거 (안지우면 느리기때문에)
ctrl+shift+w .

shifht+f12 : alt+shift+f12와 같은 기능같은데 아주 좋다 이거 자주 이용해야지 ㅋㅋ

Ctrl+K,Ctrl+K : 코드 정렬해주는거 좋다 소스 정리할때

Ctrl+M,M : Region 을 쓸때 닫고 열고 아주 유용한 단축키이다. 많이 쓸예정

Ctrl+K,S : Surround with 기능으로 try catch나 region 묶을때 유용하다


ctrl+f4 : 탭창을 닫을때 쓴다 그냥 누르고 있으면 다 닫아진다 아주 굿~


Shfit+Alt+Enter 천체 화면 코딩에 집중할때 쓴다.

정말 좋은거 발견~~~~

Shfit+Ctrl+8 : 항상 우리가 정의(F12)로 갔을때 다시 돌아오고 싶을때쓴다. 

Shfit+Ctrl+7 : 다시 돌아왔는데 다시 가고 싶을때 쓴다. 신기 신기

visual studio에서 창 다 닫는거 current 창 빼고(단축키가 기복적으로 없어서 설정해주어야함)
Options>Environment>Keyboard에서 
File.CloseAllButThis
를 찾아서 ctrl+shift+w로 바꾼다(블랜드랑 같다ㅋㅋ)

한개의 문장 선택법(아주유용하다)

마우스 (해당부분을 더블클릭)
키보드 (CTRL+Shift+화살표키)

Ctrl + "M" + "M"

코드 블록을 열었다 접었다 할 수 있는 단축키 입니다. 혼잡한 코드를 정리해서 보고 싶을 때 유용한 단축 키 입니다.
아래는 코드가 열려있는 화면입니다.

ctrl+f3 대부분 Ctrl+f 해서 찾는데 처음에 ctrl+f3을 해서 f3을 누르면 현재 커서에 있는 것을 찾는다.

Ctrl+K+S Surround with 기능이다 Try~ catch 문 같은것을 편리 하게 묶어준다^^

Ctrl+K+F 라인정렬 으로 인터넷에서 가져온 소스 정렬할때 유용 ㅋ

2012 3.19 추가

Ctrl+Alt+L 솔루션 익스플로러 바로 이동(파일찾을떄 유용) 돌아갈땐 그냥 ctrl+esc

CTRL+[ + S

이건 현재 문서가 어디에 있는 찾도록 해준다.. 이게 디폴트로 있는지 몰라서 계속 익스텐션에 있는걸 썻었는데 ㅠㅠ


Tab 이동할때

Ctrl+ALT PageUP or PageDpwn or Home or END 키로 이동 가능하다 나름 ctrl+esc보다 유용한거 같다?


모든 단축키 : http://msdn.microsoft.com/en-us/library/da5kh0wa.aspx

Posted by 동동(이재동)