2017-12-06 38 views
0

다음 xaml이 있습니다. 런타임에 다음 xaml을 동적으로 채워야하는데 필요한 것은 무엇입니까? MainWorkspaceViewModel에는 "View"라는 속성이 있습니다. 이 속성은 object 타입이므로 모든 뷰를 설정할 수 있습니다.WPF : 어떻게 뷰를 동적으로 만들 수 있습니까?

<UserControl x:Class="DesignerWorkspace.Views.MainWorkspaceView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:DesignerWorkspace.Views" 
      xmlns:vm="clr-namespace:DesignerWorkspace.ViewModels" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300">   
    <Grid> 
     <ContentControl Content="{Binding View}"/> 
    </Grid> 
</UserControl> 

답변

1

최소한 속성 변경시보기 및 업데이트가있는 컨텍스트를 추가하는 것이 좋습니다.

코드의 다른 곳에서 새보기를 설정하여 표시된보기를 관리 할 수 ​​있습니다.

다음은 추가하려는 수표가없는 단순한 구현입니다.

class MainWorkspaceViewModel : INotifyPropertyChanged 
{ 
    private object _view; 
    public object View { 
     get { return _view; } 
     set { _view = value; OnPropertyChanged(); } 
    } 
    public event PropertyChangedEventHandler PropertyChanged = delegate { }; 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

internal class MyViewManager 
{ 
    internal static MainWorkspaceView MakeMainView() 
    { 
     var view = new MainWorkspaceView(); 
     view.DataContext = new MainWorkspaceViewModel(); 
     return view; 
    } 

    internal static void UpdateView(MainWorkspaceViewModel viewmodel, object _next) 
    { 
     viewmodel.View = _next; 
    } 
    internal static void UpdateView(MainWorkspaceView view, object _next) 
    { 
     (view.DataContext as MainWorkspaceViewModel).View = _next; 
    } 
} 
+0

고마워요, 이것도 제가 조금씩 다르지만 같은 원리입니다. – Remco

1

이렇게하는 데는 여러 가지 방법이 있습니다. 먼저이 작업을 수행하는 툴킷을 사용하고 있는지 확인해야합니다. 이 툴킷의 설정 방법과 사용 방법을 확인한 후.

매우 간단한 방법으로이 도구 키트없이이 을 작성하고 어떻게 작동하는지 이해할 수 있습니다. 내 예제는 새로운 하나를 만드는 방법입니다

노트, 그것은 귀하의 경우되지 않을 수도 있습니다,하지만 그것은 단지


(새로 만들고 어떻게 작동하는지 볼 주시기) 이해의 첫번째에서 INotifyPropertyChanged를 구현하는 ViewModelBase를 작성, 바람직하게는, 다음 MainViewModel을 만들 ViewModelBase 클래스

public abstract class ViewModelBase : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 


    public virtual ICommand NavigateCommand => new RelayCommand(Navigate); 

    protected virtual void Navigate(object param) 
    { 

    } 

} 

을이 추상 클래스를 만들 그것은 ViewModelBase을 상속했고, CRE 그것의 ViewModels

를 할당하는 속성을 먹은
public class MainViewModel: ViewModelBase 
{ 
    private ViewModelBase _currentViewModel; 


    public ViewModelBase CurrentViewModel 
    { 
     get => _currentViewModel; 
     set 
     { 
      if (_currentViewModel == value) 
       return; 
      _currentViewModel = value; 

      OnPropertyChanged(nameof(CurrentViewModel)); 
     } 
    } 

    public MainViewModel() 
    { 

    } 

    protected override void Navigate(object args) 
    { 
     var namespaceName = "YourNameSpace."; 
     var className = args.ToString(); 
     var fullClassName = string.Concat(namespaceName, (string)className); 
     if (string.IsNullOrEmpty(fullClassName)) 
      return; 
     var tipo = Type.GetType(fullClassName); 
     if (tipo == null) 
      return; 

     var myObj = Activator.CreateInstance(tipo) as ViewModelBase; 
     if (myObj != null) 
      CurrentViewModel = (ViewModelBase)myObj; 

    } 

} 
당신이 MainViewModelViewModelBase (이동)의 재정의 된 메서드를 가지고 있음을 유의

, 그것은 간단한 매개 변수에서 다른 ViewModels를 여는 데 사용됩니다이 방법이다 지금

을 열고 당신이 내 예제에서, 당신의 MainWindow 콘텐츠에 메뉴와 ViewModels로 채워집니다 컨텐츠를 추가하고자하는 뷰 모델의 이름을 가진 문자열

<Window x:Class="YourNameSpace.MainWindow" 
     ....... 
     Title="MainWindow" 
     DataContext="{StaticResource MainViewModel}" > 
<Grid> 
    ..... 
    <!--In the Menu, how to open a View --> 
    <MenuItem Header="Open ViewA" Command="{Binding NavigateCommand}" CommandParameter="ViewModelA" /> 
    ....... 
    <!-- Your Content Control --> 
    <ContentControl 
      HorizontalAlignment="Center" 
      VerticalAlignment="Top" 
      HorizontalContentAlignment="Center" 
      VerticalContentAlignment="Top" 
      ClipToBounds="True" 
      Content="{Binding CurrentViewModel}" > 
    </ContentControl> 
..... 
</Window> 

보기를 만듭니다. 예 :

<Button Content="Open View A" 
     Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}, Mode=OneWay}" 
     CommandParameter="ViewModelA" Margin="5" /> 
:의 말을하자 app.xaml 파일에 지금

<UserControl x:Class="YourNameSpace.ucViewA" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      > 
    <Grid Background="White"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 


     <Grid Grid.Row="1"> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="Auto"/> 
       <ColumnDefinition Width="*"/> 
       <ColumnDefinition Width="Auto"/> 
      </Grid.ColumnDefinitions> 
      <Label Grid.Column="0" Content="this is the ViewA" Margin="5" /> 
      <Button Grid.Column="2" Content="Open View B" 
        Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}, Mode=OneWay}" 
        CommandParameter="ViewModelB" Margin="5" /> 
     </Grid> 

     <DataGrid Grid.Row="2" ColumnWidth="*" Margin="5" 
            IsReadOnly="True" 
            AutoGenerateColumns="False" 
            SelectionMode="Single" 
            HorizontalContentAlignment="Center" 

            ScrollViewer.CanContentScroll="True" 
            ScrollViewer.VerticalScrollBarVisibility="Auto" 
            ScrollViewer.HorizontalScrollBarVisibility="Auto"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Header="Column 1" MinWidth="50" Width="Auto"/> 
       <DataGridTextColumn Header="Column 2" MinWidth="140" Width="Auto"/> 
       <DataGridTextColumn Header="Column 3" MinWidth="240" Width="*"/> 
       <DataGridTextColumn Header="Column 4" MinWidth="70" Width="Auto"/> 
      </DataGrid.Columns> 
     </DataGrid> 
    </Grid> 
</UserControl> 

는 뷰 모델은 다른보기는 다음과 같은 사용에서의 UserControl

<Application x:Class="YourNameSpace.App" 
      ... 
      xmlns:local="clr-namespace:YourNameSpace" 
      StartupUri="MainWindow.xaml"> 
    <Application.Resources> 

     <local:MainViewModel x:Key="MainViewModel" /> 

     <DataTemplate DataType="{x:Type local:ViewModelA}"> 
      <local:ucViewA /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:ViewModelB}"> 
      <local:ucViewB /> 
     </DataTemplate> 

    </Application.Resources> 
</Application> 

뷰를 열 수있는 속

편집 : 깜빡했는데, ViewModel에 적어도 하나의 생성자가 있어야합니다 (비어 있음). 그래서 prob가 없습니다. lem이 발생합니다.