source

WPF MVVM 패턴을 사용한 뷰 탐색

manycodes 2023. 4. 16. 15:22
반응형

WPF MVVM 패턴을 사용한 뷰 탐색

MVVM 패턴을 사용하여 첫 WPF를 구축하고 있습니다.이 커뮤니티의 도움으로 모델, 첫 번째 View Model 및 뷰를 만들 수 있습니다.이제 기본적인 애플리케이션 레이아웃 인터페이스를 설계하는 앱에 복잡성을 더하고 싶습니다.적어도 2개의 자뷰와 1개의 메인뷰를 가지며 여러 XAML에서 이들을 분리하는 것이 제 생각입니다.

  • Main.XAML
  • 상품들.XAML
  • 클라이언트XAML

메인에는 하위 보기(제품 및 클라이언트)를 로드할 수 있는 메뉴와 공간이 있습니다.이제 MVVM 패턴에 따라 뷰 간의 모든 탐색 로직이 ViewModel에 기록되어야 합니다.그래서 4개의 View Model을 갖는 것이 아이디어입니다.

  • 메인 뷰 모델
  • 제품 뷰 모델
  • Clients View Model(클라이언트 뷰 모델)
  • 내비게이션 뷰 모델

NavigationViewModel에 하위 뷰모델 컬렉션이 포함되어 있어야 하는데 활성 뷰모델이 맞습니까?

그래서 질문하겠습니다.

1) MVVM 패턴을 사용하여 메인 뷰에 다른 뷰(제품, 클라이언트)를 로드하려면 어떻게 해야 합니까?

2) 내비게이션 view Model 구현 방법

3) 열린 뷰 또는 활성 뷰의 최대 수를 제어하려면 어떻게 해야 합니까?

4) 오픈뷰 전환 방법

많은 검색과 읽기를 했지만 메인 뷰 내에 여러 뷰를 로드하는 WPF를 사용한 MVVM 내비게이션의 간단한 작업 예를 찾을 수 없었습니다.대부분의 경우:

1) 지금은 사용하고 싶지 않은 외부 툴킷을 사용합니다.

2) 모든 뷰를 1개의 XAML 파일에 작성하기 위한 모든 코드를 넣습니다.80개 가까운 뷰를 구현해야 하기 때문에 좋은 생각은 아닌 것 같습니다.

제가 올바른 길을 가고 있는 건가요?특히 코드와 관련된 어떤 도움도 감사할 것입니다.

갱신하다

그래서 @LordTakkera의 조언에 따라 테스트 프로젝트를 작성했지만 막혔습니다..솔루션

작성자:

  • 2가지 모델(클라이언트 및 제품)

  • 1개의 메인 윈도 및2개의 wpf 사용자 컨트롤(클라이언트 및 제품) XAML.

  • 3가지 View Model (클라이언트, 제품 및 메인 View Model)

그런 다음 각 뷰의 dataContext를 해당하는 viewModel로 설정합니다.그런 다음 ContentPresenter를 사용하여 MainWindow를 만들고 뷰 모델의 속성에 바인드합니다.

메인 윈도XAML

<Window x:Class="PruevaMVVMNavNew.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="519" Width="890">    
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="80"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="20"/>
    </Grid.RowDefinitions>        
    <Border Grid.Column="0" Grid.ColumnSpan="2" Background="AntiqueWhite" ></Border>
    <Border Grid.Row="1" Grid.RowSpan="2" Background="AliceBlue"></Border>
    <Border Grid.Row="1" Grid.Column="1" Background="CadetBlue"></Border>                
    <ContentPresenter Grid.Row="1" Grid.Column="1" x:Name="ContentArea" Content="{Binding CurrentView}"/>        
    <StackPanel Margin="5" Grid.Column="0" Grid.Row="1">            
        <Button>Clients</Button>
        <Button>Products</Button>
    </StackPanel>
</Grid>

또한 Main Window의 뷰 모델입니다.

class Main_ViewModel : BaseViewModel
    {
        public Main_ViewModel()
        {
            CurrentView = new Clients();
        }

        private UserControl _currentView;
        public UserControl CurrentView
        {
            get
            {
                return _currentView;
            }
            set
            {
                if (value != _currentView)
                {
                    _currentView = value;
                    OnPropertyChanged("CurrentView");
                }
            }
        }

    }

따라서 이 로드는 기본적으로 다음과 같이 표시됩니다(적합합니다).

현재 상태

왼쪽 버튼을 특정 viemodel과 관련지어 Main view Model의 Current View속성에 바인드하는 방법이 필요합니다.내가 어떻게 그럴 수 있을까?

업데이트 2

@LordTakkera의 조언에 따라 다음과 같이 main viewModel을 변경합니다.

class Main_ViewModel : BaseViewModel
    {
        public ICommand SwitchViewsCommand { get; private set; }

        public Main_ViewModel()
        {
            //CurrentView = new Clients();
            SwitchViewsCommand = new RelayCommand((parameter) => CurrentView = (UserControl)Activator.CreateInstance(parameter as Type));
        }

        private UserControl _currentView;
        public UserControl CurrentView
        {
            get
            {
                return _currentView;
            }
            set
            {
                if (value != _currentView)
                {
                    _currentView = value;
                    OnPropertyChanged("CurrentView");
                }
            }
        }
    }

DelegateCommand 대신 RelayCommand를 사용하지만 동일한 방식으로 작동합니다.버튼을 누르면 명령어가 실행되고 type parameter 문자열은 OK이지만 다음 오류가 나타납니다.

에러

변환: 값은 null일없습니다. 파라미터 이름: type. 제안: 개체 인스턴스를 만들려면 New 키워드를 사용합니다. New 키워드를 어디에 넣어야 할지 모르겠습니다.Command Parameter를 사용해 봤지만 동작하지 않습니다.감 잡히는 게 없어요?감사해요.

업데이트 3

여기에서 받은 모든 조언과 도움, 그리고 많은 작업을 통해 최종 내비게이션 메뉴와 애플리케이션 인터페이스 기반을 소개합니다.

캡처 1 캡처 2

별도의 "내비게이션" 뷰 모델이 필요한지 잘 모르겠습니다. 메인 화면으로 쉽게 이동할 수 있습니다.어느 쪽이든:

"자녀" 보기를 구분하기 위해 "메인" 보기에서 간단한 ContentPresenter를 사용합니다.

<ContentPresenter Content="{Binding CurrentView}"/>

하는 가장 쉬운 은 이 을 ""로 입니다.UserControl그러나 일부에서는 (ViewModel이 현재 "View" 클래스에 종속되어 있기 때문에) MVVM에 위반된다고 주장할 수 있습니다.물건으로 만들 수는 있지만 안전성이 떨어집니다.UserControl을 사용합니다.

이들 사이를 전환하려면 일종의 선택 컨트롤이 필요합니다.라디오 버튼은 전에도 해봤는데 이렇게 바인드하면 됩니다.

<RadioButton Content="View 1" IsChecked="{Binding Path=CurrentView, Converter={StaticResource InstanceEqualsConverter}, ConverterParameter={x:Type views:View1}"/>

변환기는 매우 간단합니다. "Convert"에서는 현재 컨트롤이 파라미터의 유형인지 여부를 확인하고 "ConvertBack"에서는 파라미터의 새 인스턴스를 반환합니다.

public class InstanceEqualsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (parameter as Type).IsInstanceOfType(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (bool)value ? Activator.CreateInstance(parameter as Type) : Binding.DoNothing;
    }
}

콤보 상자 또는 다른 선택 컨트롤에 바인딩하는 것도 비슷한 패턴을 따릅니다.

물론 DataTemplates(실렉터 포함)를 사용하여 병합된 사전(별도의 XAML 허용)을 사용하여 리소스에 로드할 수도 있습니다.저는 개인적으로 사용자 제어 경로를 선호합니다. 당신에게 가장 적합한 경로를 선택하세요!

이 접근방식은 "한 번에 하나의 뷰"입니다.여러 뷰로 비교적 쉽게 변환할 수 있습니다(UserControl은 사용자 컨트롤의 집합이 됩니다).를 사용합니다.변환기 등에 들어 있습니다).

버튼을 사용하여 이 작업을 수행하려면 명령어를 사용하고 명령어 파라미터를 활용합니다.

XAML 버튼은 다음과 같습니다.

<Button ... Command={Binding SwitchViewsCommand} CommandParameter={x:Type local:ClientsView}/>

다음으로 컨버터에서 액티베이터 코드를 실행하는 위임 명령(여기서 설명)이 있습니다.

public ICommand SwitchViewsCommand {get; private set;}

public MainViewModel()
{
    SwitchViewsCommand = new DelegateCommand((parameter) => CurrentView = Activator.CreateInstance(parameter as Type));
}

지금 당장은 아니지만, 꽤 가까울 겁니다.어떻게 되어가는지 알려줘!

추가 정보가 있으면 알려주세요!

업데이트:

고객의 우려에 대한 답변:

  1. 예, 버튼을 누를 때마다 보기의 새 인스턴스가 생성됩니다.이 문제를 쉽게 해결할 수 있습니다.Dictionary<Type, UserControl>미리 생성된 보기와 인덱스를 포함하는 파일입니다.그 문제에 대해서는,Dictonary<String, UserControl>변환기 파라미터로 단순한 문자열을 사용합니다.단점은 View Model이 표시할 수 있는 뷰의 종류와 밀접하게 결합된다는 것입니다(해당 사전을 채워야 하기 때문입니다).

  2. 클래스는 다른 사람이 참조를 보유하지 않는 한 폐기해야 합니다(등록한 이벤트 핸들러).

  3. 지적하신 것처럼 한 번에 하나의 뷰만 생성되므로 메모리에 대해 걱정할 필요가 없습니다.물론 컨스트럭터를 부르고 있지만, 특히 CPU의 여유 시간이 많은 최신 컴퓨터에서는 그렇게 비싸지 않습니다.퍼포먼스 질문에 대한 답변은 항상 "벤치마크"입니다.왜냐하면 의도된 도입 타깃과 전체 소스에 액세스하여 실제로 가장 뛰어난 성능을 얻을 수 있는 것은 고객뿐이기 때문입니다.

IMHO는 내비게이션이 이미 구현되어 있기 때문에 MVVM 프레임워크(PRISM, MMVM Light, Chinch 등)를 사용하는 것이 가장 좋습니다.직접 네비게이션을 만들려면 DataTemplate를 사용해 보십시오.

언급URL : https://stackoverflow.com/questions/22793164/wpf-navigate-through-views-using-mvvm-pattern

반응형