2014-12-16 1 views
1

기본적으로 마크 업 문제가 있습니다. 몇 가지 해결책을 생각해 냈지만 도움이되지만 느끼지 못할 것 같습니다. 당신이 내 복잡한 경로를 안내하기보다는 가장 간단한 구현을 공유하고 어떻게 처리 할지를 물어 보았습니다.WPF :보기 내에서 ViewModel을 만드는 방법

에서 MainPage.xaml 위의 예를 감안할 때, 내가 명령이 차량을 만들 수있는 제약 주어진보기에 그리드의 내용을 얻을 수있는 방법 이외의 DataContext에의 할 수

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto" /> 
     <ColumnDefinition Width="6" /> 
     <ColumnDefinition /> 
     <ColumnDefinition Width="Auto" /> 
     <ColumnDefinition Width="6" /> 
     <ColumnDefinition /> 
     <!--Additional Columns--> 
    </Grid.ColumnDefinitions> 
    <!--Row Definitions--> 
    <Label Grid.Row="0" Grid.Column="0" Content="Vin:" HorizontalAlignment="Right" /> 
    <ctrl:CommandTextBox Grid.Row="0" Grid.Column="2" Command="{Binding CreateVehicleCommand}" CommandParameter="{Binding Text, RelativeSource={RelativeSource Self}}" /> 
    <Label Grid.Row="0" Grid.Column="3" Content="Manufacturer:" HorizontalAlignment="Right" /> 
    <TextBox Grid.Row="0" Grid.Column="5" IsEnabled="False" Text="{Binding Vehicle.Manufacturer, Mode=OneWay}" /> 
    <!--Additional Read Only Values--> 
</Grid> 

입니다 만든 (차량)?

내 특정 시도를보고 할 경우

는 그 질문에 내가 명령이 차량이 만들 수있는 제약 주어진보기에 그리드의 내용을 얻을 수있는 방법 여기 UserControl's DependencyProperty is null when UserControl has a DataContext

+0

고민중인 부분이 보이지 않습니다. 모델을 뷰 모델에 삽입 할 수없는 이유는 무엇입니까? 왜 TextBox를 깨뜨릴까요? ViewModel이 데이터를 얻는 방법을 변경하면 View에 영향을 미칠 수 있습니다. – BradleyDotNET

+0

@BradleyDotNET 당신이 맞습니다, 내가 보여준 것들이 효과가 있습니다. 그러나 그것은 틀린 것처럼 보인다? 내 뷰 모델의 팩토리를 뷰 모델의 생성으로 덮어 쓴 자리 표시 자 뷰 모델에 삽입해야한다고 생각하지 않습니다. 내 viewmodel과 공장 용으로 두 번째 DataContext를 제공하기 위해 UserControl을 확장 할 수 있을지 궁금해지기 시작 했나요? –

+0

솔직히? 당신의 전체적인 디자인은 어리석게도 복잡하게 보인다. 왜 공장이 필요하니? Btw, 나는 당신이 묘사 한 과정이 대단히 복잡한 것처럼 보인 데 동의한다. 그렇다면 다시 디자인이 그렇게됩니다. – BradleyDotNET

답변

0

나는 뭔가를 생각해 냈습니다. 나는 비교적 행복합니다. 이로 인해 100 개의 복합 ViewModel을 만들지 못하게되었고 불필요한 복잡성이 생겨도 필자가 작성해야하는 복사/붙여 넣기 코드의 양이 크게 줄어 들었습니다.

VMFactoryViewModel.cs

public class CreatedViewModelEventArgs<T> : EventArgs where T : ViewModelBase 
{ 
    public T ViewModel { get; private set; } 

    public CreatedViewModelEventArgs(T viewModel) 
    { 
     ViewModel = viewModel; 
    } 
} 

public class VMFactoryViewModel<T> : ViewModelBase where T : ViewModelBase 
{ 
    private Func<string, T> _createViewModel; 
    private RelayCommand<string> _createViewModelCommand; 
    private readonly IDialogService _dialogService; 

    /// <summary> 
    /// Returns a command that creates the view model. 
    /// </summary> 
    public ICommand CreateViewModelCommand 
    { 
     get 
     { 
      if (_createViewModelCommand == null) 
       _createViewModelCommand = new RelayCommand<string>(x => CreateViewModel(x)); 

      return _createViewModelCommand; 
     } 
    } 

    public event EventHandler<CreatedViewModelEventArgs<T>> CreatedViewModel; 

    private void OnCreatedViewModel(T viewModel) 
    { 
     var handler = CreatedViewModel; 
     if (handler != null) 
      handler(this, new CreatedViewModelEventArgs<T>(viewModel)); 
    } 

    public VMFactoryViewModel(IDialogService dialogService, Func<string, T> createViewModel) 
    { 
     _dialogService = dialogService; 
     _createViewModel = createViewModel; 
    } 

    private void CreateViewModel(string viewModelId) 
    { 
     try 
     { 
      OnCreatedViewModel(_createViewModel(viewModelId)); 
     } 
     catch (Exception ex) 
     { 
      _dialogService.Show(ex.Message); 
     } 
    } 
} 

VMFactoryUserControl.cs

public class VMFactoryUserControl<T> : UserControl where T : ViewModelBase 
{ 
    public static readonly DependencyProperty VMFactoryProperty = DependencyProperty.Register("VMFactory", typeof(VMFactoryViewModel<T>), typeof(VMFactoryUserControl<T>)); 

    public VMFactoryViewModel<T> VMFactory 
    { 
     get { return (VMFactoryViewModel<T>)GetValue(VMFactoryProperty); } 
     set { SetValue(VMFactoryProperty, value); } 
    } 
} 

GenericView.XAML

<ctrl:VMFactoryUserControl x:Class="GenericProject.View.GenericView" 
          x:TypeArguments="vm:GenericViewModel" 
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
          xmlns:ctrl="clr-namespace:SomeProject.Controls;assembly=SomeProject.Controls" 
          xmlns:vm="clr-namespace:GenericProject.ViewModel"> 
    <Grid> 
     <!-- Column Definitions --> 
     <!-- Row Definitions --> 
     <Label Grid.Row="0" Grid.Column="0" Content="Generic Id:" HorizontalAlignment="Right" /> 
     <ctrl:CommandTextBox Grid.Row="0" Grid.Column="2" 
          Command="{Binding VMFactory.CreateViewModelCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" 
          CommandParameter="{Binding Text, RelativeSource={RelativeSource Self}}" /> 
     <Label Grid.Row="0" Grid.Column="3" Content="Generic Property:" HorizontalAlignment="Right" /> 
     <TextBox Grid.Row="0" Grid.Column="5" IsEnabled="False" Text="{Binding GenericProperty, Mode=OneWay}" /> 
     <!--Additional Read Only Values--> 
    </Grid> 
</ctrl:VMFactoryUserControl> 

GenericView.xaml.cs

public partial class GenericView : VMFactoryUserControl<GenericViewModel> 
{ 
    public GenericView() 
    { 
     InitializeComponent(); 
    } 
} 

MainPageViewModel.cs

public class MainPageViewModel : ViewModelBase 
{ 
    private readonly IDialogService _dialogService; 
    private GenericViewModel _generic; 
    private readonly VMFactoryViewModel<GenericViewModel> _genericFactory; 

    public GenericViewModel Generic 
    { 
     get { return _generic; } 
     private set 
     { 
      if (_generic != value) 
      { 
       _generic = value; 
       base.OnPropertyChanged("Generic"); 
      } 
     } 
    } 

    public VMFactoryViewModel<GenericViewModel> GenericFactory 
    { 
     get { return _genericFactory; } 
    } 

    private void OnGenericFactoryCreatedViewModel(object sender, CreatedViewModelEventArgs<GenericViewModel> e) 
    { 
     Generic = e.ViewModel; 
    } 

    public MainPageViewModel(IDialogService dialogService) 
    { 
     _dialogService = dialogService; 

     _genericFactory = new VMFactoryViewModel<GenericViewModel>(_dialogService, x => new GenericViewModel(_dialogService, GetGeneric(x))); 
     _genericFactory.CreatedViewModel += OnGenericFactoryCreatedViewModel; 
    } 

    private Generic GetGeneric(string genericId) 
    { 
     // Return some Generic model. 
    } 
} 

에서 MainPage.xaml

<Page x:Class="GenericProject.MainPage" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:vw="clr-namespace:GenericProject.View"> 
    <StackPanel> 
     <!-- Headers and Additional Content. --> 
     <vw:EventView DataContext="{Binding Generic}" 
         VMFactory="{Binding DataContext.GenericFactory, RelativeSource={RelativeSource AncestorType={x:Type Page}}}" /> 
    </StackPanel> 
</Page> 
0

입니다 생성 될 DataContext (Vehicle)?

MVVM 문제 이상의 경쟁 조건입니다. 문제를 먼저 해결할 것이지만 그 후에는 제 2의 제안을하십시오.

  1. 거기 뷰 모델을 참고로 다른 뷰 모델을 포함 할 수없는 어떤 이유가없고 그 기준은에서 INotifyPropertyChanged의 mechanisim를 사용하여 바인딩됩니다.
  2. xaml (view) 페이지에 페이지 (view)가 DataContext에서 직접 사용하지 않는 ViewModel에 대한 정적 참조가 포함되어 있지만 특정 컨트롤이 포함 된 데이터 컨텍스트 외부의 해당 정적에 바인딩 할 수 없음 제어.

어느 쪽이든 하나는 데이터를 얻을하거나 데이터를 취득하는 대체 배관을 제공하기 위해 자체를 가리키는 액세스를 (뿐만 아니라 당신이을 제공하는 다른 게시물에 대한 응답에서 언급) 제공 할 수 있습니다.


또는 이러한 상황이 발생하지 않고 제어뿐만 아니라 그리드가 적절한 형식으로 정보를 액세스 할 수 있도록이 이럴 경쟁 조건이 더 많은 정보를 포함하고 처리하도록 뷰 모델을 평평하게 할 수 있습니다.

지금은 해결해야 할 디자인 목표와 위험을 잘 알고 있기 때문에이 문제를 완전히 해결할 수 없습니다.

+0

경쟁 조건에 대한 귀하의 우려를 잘 모르겠습니다. 나는 복합 ViewModel의 생성에 관한 많은 옵션이 있다는 것을 알고있다. MainPageViewModel은 합성물이며, 마찬가지로 CreateVehicleCommand와 VehicleViewModel이 포함 된 SubPageViewModel을 만들 수 있습니다. 나는 이것이 나를 매우 멀리하게하는 것처럼 느끼지 않는다. 내가 뭘 하려는지 ViewModel의 자체 및 표시 속성에 설 수있는 뷰를 만드는 것입니다. 이 뷰에 ViewModel을 생성하는 기능이 포함되어 있습니다. –

+0

@FrumRoll 항목을 만드는보기에 대해 어떤 의미인지 알 수 있습니다. 문제는 전체 VM을 컨트롤에 보내려고하는 것일 수 있습니다. 새로 생성 된 VM의 실제 항목을 개별 종속성 속성으로 분리 한 경우에는 어떻게해야합니까? 컨트롤 안에는 데이터의 전체 집합을 찾고 컨트롤을 '켜는'메서드를 호출하는 각 속성에 대한 변경 알림이 있습니다. (나는 Silverlight 프로젝트에서 비슷한 결과를 보았습니다.) 만약 내가 여전히 압정에서 벗어난다면; 그냥 내 생각을 무시하십시오. – OmegaMan

관련 문제