2013-04-23 10 views
0

Я работаю над проектом WPF. Это мой XAML код:ComboBox привязка к пользовательскому ViewModel

<Window x:Class="MyNamespace.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:l="clr-namespace:MyNamespace" 
     xmlns:p="clr-namespace:MyNamespace.Properties" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Height="500" Title="{x:Static p:Resources.Title}" Width="500" 
     WindowStartupLocation="CenterScreen"> 
    <Window.Resources> 
     <l:BrowsersViewModel x:Key="BrowsersViewModel"/> 
    </Window.Resources> 
    <Canvas Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" 
      DataContext="{StaticResource BrowsersViewModel}"> 
     <ComboBox Canvas.Left="10" Canvas.Top="10" DisplayMemberPath="Name" 
        ItemsSource="{Binding Path=Items}" 
        SelectedItem="{Binding Mode=TwoWay, Path=SelectedItem}" 
        SelectedValuePath="Process" Width="379"/> 
     <Button Content="Repopulate" Canvas.Right="10" 
       Canvas.Top="10" Width="75"/> 
    </Canvas> 
</Window> 

И это мой ViewModel код:

// BrowserInstance is a simple struct with two public fields: 
// 1) System.Diagnostics.Process Process 
// 2) System.String Name 
public sealed class BrowsersViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private BrowserInstance m_SelectedItem; 
    public BrowserInstance SelectedItem 
    { 
     get { return m_SelectedItem; } 
     set 
     { 
      if (m_SelectedItem != value) 
      { 
       m_SelectedItem = value; 
       NotifyPropertyChanged("SelectedItem"); 
      } 
     } 
    } 

    private ObservableCollection<BrowserInstance> m_Items; 
    public ObservableCollection<BrowserInstance> Items 
    { 
     get { return m_Items; } 
     set 
     { 
      if (m_Items != value) 
      { 
       m_Items = value; 
       NotifyPropertyChanged("Items"); 
      } 
     } 
    } 

    public BrowsersViewModel() 
    { 
     m_Items = new ObservableCollection<BrowserInstance>(); 
     Populate(); 
    } 

    private void NotifyPropertyChanged(String propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, (new PropertyChangedEventArgs(propertyName))); 
    } 

    public void Populate() 
    { 
     foreach (Process process in Process.GetProcessesByName("chrome")) 
     { 
      BrowserInstance instance = new BrowserInstance(); 
      instance.Process = process; 
      instance.Name = "[Chrome] " 
         + process.Handle.ToString() 
         + " " + ((process.MainWindowTitle.Length > 0) ? 
             process.MainWindowTitle : "NULL"); 

      m_Items.Add(instance); 
     } 

     NotifyPropertyChanged("Items"); 
    } 
} 

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

1) Я вижу много значений внутри выпадающего списка ComboBox, но все они пустые. Я хотел бы отобразить свойство BrowserInstance.Name внутри ComboBox и получить значение BrowserInstance.Process при выборе элемента.

2) Когда приложение запускается, выполняется проверка текущих запущенных процессов браузера, чтобы заполнить ComboBox. Если не найдены запущенные экземпляры, как я могу отобразить сообщение внутри моего ComboBox, например «Нет экземпляров, которые были найдены!»?

3) Если один или несколько экземпляров браузера найдены, когда статистика приложения, как я могу выбрать первый по умолчанию?

4) Кнопка Repopulate будет использоваться для повторной проверки экземпляров браузера пользователями. Предположим, что ранее выбранный экземпляр все еще работает ... как я могу сохранить выбранный? И если ранее выбранные экземпляры больше не запускаются, как я могу выбрать по умолчанию первый раз еще раз?

Большое спасибо!

EDIT: Вот мой текущий код

MainWindow:

public MainWindow() 
{ 
    InitializeComponent(); 
    DataContext = m_BrowserInstances = new BrowserInstancesViewModel(); 
} 

private void OnClickButtonRefresh(Object sender, RoutedEventArgs e) 
{ 
    m_BrowserInstances.Populate(); 
} 

BrowserInstancesViewModel:

public void Populate() 
{ 
    BrowserInstance selectedItem = m_SelectedItem; 
    List<BrowserInstance> items = new List<BrowserInstance>(); 

    foreach (Process process in Process.GetProcessesByName("chrome")) 
     items.Add(new BrowserInstance(process)); 

    if (items.Count > 0) 
    { 
     m_Items = new ObservableCollection<BrowserInstance>(items.OrderBy(x => x.Process.Id)); 

     if ((selectedItem != null) && (m_Items.SingleOrDefault(NewMethod(selectedItem)) != null)) 
      m_SelectedItem = selectedItem; 
     else 
      m_SelectedItem = m_Items[0]; 

     m_Enabled = true; 
    } 
    else 
    { 
     m_Items = new ObservableCollection<BrowserInstance>() { (new BrowserInstance()) }; 
     m_SelectedItem = m_Items[0]; 

     m_Enabled = false; 
    } 

    NotifyPropertyChanged("Enabled"); 
    NotifyPropertyChanged("Items"); 
    NotifyPropertyChanged("SelectedItem"); 
} 
+0

Почему вы используете структуру? вместо этого создайте класс. –

+0

Хорошо, но результат не меняется. Я все еще испытываю первый вопрос ... –

+0

копировать наклеенный код, я не могу реплицировать первую проблему, здесь все работает – dnr3

ответ

1

1) Я не могу воспроизвести эту проблему, вы уверены, что есть процесс работает хром?: D

2) вы можете взломать это следующим образом:: D

 <ComboBox Canvas.Left="10" Canvas.Top="10" 
       DisplayMemberPath="Name" ItemsSource="{Binding Path=Items}" 
       SelectedItem="{Binding Mode=TwoWay, Path=SelectedItem}" 
       SelectedValuePath="Process" Width="200"> 
     <ComboBox.Style> 
      <Style TargetType="ComboBox"> 
       <Setter Property="IsEnabled" Value="True"/> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding Path=Items.Count}" Value="0"> 
         <Setter Property="IsEnabled" Value="False"/> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </ComboBox.Style> 
    </ComboBox> 
    <TextBlock Canvas.Left="10" Canvas.Top="10" 
       Text="No instances have been found!" > 
     <TextBlock.Style> 
      <Style TargetType="TextBlock"> 
       <Setter Property="Visibility" Value="Collapsed"/> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding Path=Items.Count}" Value="0"> 
         <Setter Property="Visibility" Value="Visible"/> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </TextBlock.Style> 
    </TextBlock> 

или еще лучше вы retemplate выпадающего включить TextBlock и связать его видимость с помощью hasitems значения свойства выпадающего списка (конечно вы необходимо использовать BoolToVis преобразователь)

3) добавить этот код в конструктор Vm после заполнения

if (m_Items.Count > 0) 
{ 
    SelectedItem = m_Items[0]; 
} 

4) добавить новый метод заселить в виртуальную машину и магазин т он тока SelectedItem, заселить, проверьте, существует ли или нет, повторно выберите пункт

public void Repopulate() 
    { 
     BrowserInstance currentSelectedItem = m_SelectedItem; 
     Populate(); 

     if (m_Items.Count>0) 
     { 
      if (currentSelectedItem !=null 
       && m_Items.FirstOrDefault 
        ((bi) => bi.Process == currentSelectedItem .Process) 
         != null) 
      { 
       SelectedItem = currentSelectedItem; 
      } 
      else 
      { 
       SelectedItem = m_Items[0]; 
      } 
     } 
    } 

NB:
Я не уверен, что свойство, чтобы проверить, чтобы проверить наличие экземпляра becoz, когда я пытался выше кода и отладки это мой хромовый список процессов меняется. но в основном это то, что вы могли бы сделать

+0

Все работает отлично, используя ваш метод, но я думаю, что равенство процесса не работает должным образом, и я никогда не возвращу ранее выбранный элемент. Я изменил его, чтобы сравнить MainModule.BaseAddress и Id, теперь он работает, но я все еще не могу его выбрать. –

+0

@ Zarathos Да, проверка равенства испорчена, как я заявил в примечании: D, сохранили ли m_selecteditem локальную переменную? owh да, еще одна вещь, я не воссоздал m_items, я просто очистил ее в начале метода заполнения – dnr3

3

BrowserInstance простая структура с двумя общими полями:

WPF Не поддерживает привязку данных к полям. Только свойства.

Это должно работать:

public class BrowserInstance 
{ 
    public string Name { get; set; } 

    public Process Process { get; set; } 
} 
+0

+1, Для привязки данных нам нужны свойства. BTW, struct также будет работать, если мы изменим поля на свойства. – Manish

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