page에서 windows의 ViewModel을 사용할 수 없나요?

MainWindow.xaml에서 버튼을 클릭하면 Frame 내 표시될 Content를 변경하는
ViewModel.cs를 코드를 작성했습니다.

  • CommandParameter로 전달 받은 페이지와 동일한 이름의 페이지를 CurrentPage에 할당하고, 변경됨을 알림
//ViewModel.cs 
public ICommand PageChange
{
    get
    {
        _PageChange ??= new Command.RelayCommand(PageChangAction, CurrentPageChaeckNot);
        return _PageChange;
    }
}

private void PageChangAction(object obj)
{
    foreach (var page in _page)
    {
        if (obj.Equals(page.GetType().Name))
        {
            _CurrentPage = page;
            OnPropertyChanged(nameof(CurrentPage));
            break;
        }

    }
}

private bool CurrentPageChaeck(object obj)
{
    if (obj == null) return false;
    string objStr = obj.ToString() ?? "";
    if (objStr.ToString().ToLower() == _CurrentPage.GetType().Name.ToLower())
    {
        return true;
    }
    return false;
}
private bool CurrentPageChaeckNot(object obj)
{
    return !CurrentPageChaeck(obj);
}
//MainWindow.xaml
<Window>
    <Window.DataContext>
        <local:ApplicationViewModel/>
    </Window.DataContext>

    <DockPanel>
       <Grid DockPanel.Dock="Left" >
            <Button Content="go page2" Command="{Binding PageChange}" CommandParameter="page2"  />
        </Grid>

        <Grid DockPanel.Dock="Right">
            <Frame x:Name="pageView" NavigationUIVisibility="Hidden" Content="{Binding CurrentPage}"/>
        </Grid>
    </DockPanel>
</Window>

Frame의 Content page 내에서 Frame를 Content 를 변경하고 싶은데,
커멘드가 동작하지 않네요 …
혹시 방법을 아시는 분이 계신가요?

//Frame의 Content에 표시되는 page.xaml
<Page xmlns:root="clr-namespace:sample" d:DataContext="{d:DesignInstance Type=sample:ViewModel}">
    <Grid>
        <StackPanel Orientation="Vertical">
            <Button Content="go page1" Command="{Binding PageChange}"  CommandParameter="page1" />
        </StackPanel>
    </Grid>
</Page>

1 Like

원인 분석

WPF의 Frame은 "탐색(Navigation) 가능한 콘텐츠 호스팅"이라는 개념에 의해 DataContext와 같이 FrameworkPropertyMetadataOptions.Inherits 특성을 갖는 속성 값이 하위 요소에 전파되지 않는 특성이 있습니다.

쉽게 말해서 Frame은 HTML의 iframe 태그와 비슷한 개념으로 하위 요소가 Visual Tree 계층 구조상에 존재하지만 상위 요소에서 계승(Inherit)되는 속성은 격리되는 독립적인 컨테이너 입니다. 또한 브라우저 기반 어플리케이션(XBAP)에서 iframe과 유사한 개념을 지원하기 위해 제공되는 클래스입니다.

Dependency property value inheritance - WPF .NET | Microsoft Learn

… 속성 값 상속은 상속된 값을 불연속적인 논리 트리를 통해 전달할 수 있지만 상속 가능한 속성이 연결된 속성으로 등록되고 Frame과 같은 의도적인 상속 차단 경계가 없는 경우에만 가능합니다.

… Property value inheritance is able to pass inherited values through a discontinuous logical tree, but only if the inheritable property was registered as an attached property and there isn’t a deliberate inheritance-blocking boundary, such as a Frame.

관련 답변

번역

질문에 대한 답변으로, 이 동작에 관한 공식적인 문서는 아니지만, 두 권의 WPF 책에서 이와 관련된 내용을 언급하고 있습니다.

“Essential Windows Presentation Foundation” (pp. 160-161)에서는 다음과 같이 설명하고 있습니다:

탐색 가능한 콘텐츠를 호스팅하는 두 가지 흥미로운 모델이 있습니다: 격리된 호스팅통합된 호스팅입니다.

격리된 호스팅에서는 콘텐츠가 신뢰되지 않으며 완전히 격리된 (샌드박스된) 환경에서 실행됩니다. 이는 WPF 콘텐츠가 시스템 웹 브라우저에서 XAML 브라우저 애플리케이션으로 실행될 때 호스팅되는 방식입니다. 다른 애플리케이션이나 HTML 콘텐츠로의 탐색을 위해, Frame에서는 이 격리된 호스팅 모델을 지원합니다.

통합된 호스팅, 즉 콘텐츠가 애플리케이션의 일부처럼 동작하도록 하는 것은 시스템에서 전혀 지원되지 않습니다. Frame이 애플리케이션 내의 콘텐츠로 탐색할 때, 우리는 격리된 것과 통합된 행동의 기이한 혼합을 얻습니다. Frame은 콘텐츠를 스타일 (그리고 부모의 스타일)과는 격리하지만 애플리케이션의 스타일과는 격리하지 않습니다. 이벤트는 Frame 내의 콘텐츠로부터 버블되지 않습니다; 그러나 객체들은 Content 속성에서 접근할 수 있습니다 (이는 보안적 의미에서 격리되지 않았음을 의미합니다).

이러한 모든 이유로, Frame은 외부 콘텐츠를 작업할 때 가장 유용하지만, 애플리케이션 콘텐츠에 대해서도 신중하게 사용될 수 있습니다.

여기까지가 이 책에서 설명하는 전부입니다 – 속성 상속에 관한 내용은 없습니다.

“Windows Presentation Foundation Unleashed” (p. 95)에서는 다음과 같이 설명하고 있습니다:

Frame 컨트롤은 다른 모든 콘텐츠 컨트롤과 마찬가지로 임의의 콘텐츠를 포함하지만, 나머지 UI와는 콘텐츠를 격리시킵니다. 예를 들어, 일반적으로 요소 트리 아래로 상속되는 속성들이 Frame에 도달하면 멈춥니다.

해결 방안

수동으로 PageDataContext 값을 지정

MainWindow.xaml

<Frame x:Name="pageView" NavigationUIVisibility="Hidden" Content="{Binding CurrentPage}"
   LoadCompleted="pageView_OnLoadCompleted" />

MainWindow.xaml.cs

private void pageView_OnLoadCompleted(object sender, NavigationEventArgs e)
{
  if (pageView.Content is FrameworkElement content)
        content.DataContext = pageView.DataContext;
}

ContentControlUserControl 사용

다만 FramePage는 과거 브라우저 기반 어플리케이션(XBAP) 등 페이지 기반 어플리케이션을 제작하기 위한 요소인데 일반적인 독립 실행 WPF 데스크탑 어플리케이션에서는 잘 사용하지 않는 개념인 것 같습니다. (.NET Framework 3.5때 부터 WPF를 사용했지만 Page 클래스를 한 번도 사용한 적 없음)

따라서 혹시 Page를 사용하는 명확한 이유가 없으시다면 FramePage 대신 ContentControlUserControl을 사용하시는게 어떨까 합니다.

3 Likes

답변감사합니다.
UserControl을 사용하여 처리 했습니다 !

2 Likes