2016-11-07 5 views
1

Я новичок в WPF и MVVM. Я пытаюсь разобраться, как иметь чистую структуру проекта, где есть несколько кнопок, запускающих разные приложения (например, хром, IE, блокнот). Возможно ли иметь один ViewModel для нескольких кнопок?Модель одного вида для нескольких кнопок

Я начал с использования кода от here, и моя попытка решения состоит в том, чтобы сделать код с этой ссылкой базой модели представления и иметь другие модели просмотра для каждой кнопки, которые расширяют указанную базу.

Каждый из них имеет уникальную акцию:

public override void ClickAction() 
    { 
     Process ieProcess = new Process(); 
     ieProcess.StartInfo.FileName = "IExplore.exe"; 
     ieProcess.Start(); 
    } 

Однако я не уверен в правильном пути идти об этом. Как создать DataContext с таким подходом? Любая помощь приветствуется.

+1

Почему каждая кнопка имеет свой собственный контекст данных для начала? Если вы не находитесь в элементе управления, это звучит неправильно. – BradleyDotNET

+0

Спасибо за ответ. Как я уже сказал, я новичок в этом и с трудом хватаю шаблон дизайна. Можете ли вы сделать предложение о том, что я должен делать по-другому/как подойти к этому? –

+0

Два предложения, по сути :) – BradleyDotNET

ответ

5

У вас должна быть одна модель просмотра за просмотр; а не на элемент в вашем представлении (в данном случае, кнопки). Самый простой способ сделать то, что вы бы с описанием будет использовать CommmandParameter свойство проходить в именах ехе:

<Button Content="Launch IE" Command="{Binding LaunchAppCommand}" CommandParameter="IExplorer.exe"/> 
<Button Content="Launch Notepad" Command="{Binding LaunchAppCommand}" CommandParameter="notepad.exe"/> 
<Button Content="Launch Chrome" Command="{Binding LaunchAppCommand}" CommandParameter="chrome.exe"/> 

С вашей командой:

public ICommand LaunchAppComand {get; private set;} 
... 
public MyViewModel() 
{ 
    LaunchAppCommand = new DelegateCommand(LaunchApp); 
} 
... 
private void LaunchApp(object parameter) 
{ 
    string processName = (string)parameter; 
    Process launchProc = new Process(); 
    launchProc.StartInfo.FileName = processName; 
    launchProc.Start(); 
} 

Чтобы избежать жесткого кодирования все ваши кнопки вы могли бы используйте ItemsControl, который устанавливает индивидуальный контекст данных для каждого создаваемого шаблона. Для этого вам нужна коллекция классов данных, и немного другой способ добраться до вашей команды:

//ProcessShortcut.cs 
public class ProcessShortcut 
{ 
    public string DisplayName {get; set;} 
    public string ProcessName {get; set;} 
} 

//MyViewModel.cs, include the previous code 

//INotifyPropertyChanged left out for brevity 
public IEnumerable<ProcessShortcut> Shortcuts {get; set;} 

public MyViewModel() 
{ 
    Shortcuts = new List<ProcessShortcut>() 
    { 
     new ProcessShortcut(){DisplayName = "IE", ProcessName="IExplorer.exe"}, 
     new ProcessShortcut(){DisplayName = "Notepad", ProcessName="notepad.exe"}, 
     new ProcessShortcut(){DisplayName = "Chrome", ProcessName="chrome.exe"}, 
    }; 
} 

//MyView.xaml 
<Window x:Name="Root"> 
... 
    <ItemsControl ItemsSource="{Binding Shortcuts}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Button Content="{Binding DisplayName, StringFormat='{}Start {0}'}" 
         Command="{Binding ElementName=Root, Path=DataContext.LaunchAppCommand}" 
         CommandParameter="{Binding ProcessName}"/> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
... 
</Window> 

Поскольку ItemsControl устанавливает DataContext внутри шаблон для связанного элемента вам нужно ElementName связывания, чтобы получить к команде, и не нужно квалифицировать доступ к членам ProcessShortcut. В конечном счете, это подход, который вы обычно хотите предпринять, когда у вас есть повторяющиеся элементы управления, подобные этому.

+0

Большое спасибо за вашу помощь. Определенно большое объяснение и начало моего учебного процесса! Я нашел реализацию DelegateCommand в Интернете, которая кажется достаточной, есть ли у вас какие-либо данные/советы по этому поводу? Кажется, что Microsoft не использует его. –

+0

@AlexRosenfeld Онлайн-реализации узумально прекрасны; но их реализация «CanExecuteChanged» исключительно неэффективна, если они используют CommandManager.RequerySposed (см. http://stackoverflow.com/a/3408591/1783619). Пока вы избегаете того, что большинство из них хороши – BradleyDotNET

+0

Хорошо, еще раз спасибо! В настоящее время что-то не так с привязкой команды клика, она не вызывает никаких вызовов LaunchAppCommand. Я займусь этим некоторое время и отправлю последующее сообщение, если я не смогу его получить. Вы очень помогли –

Смежные вопросы