0

我正在开发一个 WPF 项目。这是我的 XAML 代码:

<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 按钮将用于重新检查用户正在运行的浏览器实例。假设之前选择的实例仍在运行……我怎样才能让那个实例保持选中状态?如果之前选择的实例不再运行,我如何再次默认选择第一个?

非常感谢!

编辑:这是我当前的代码

主窗口:

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");
}
4

2 回答 2

3

BrowserInstance 是一个具有两个公共字段的简单结构:

WPF 不支持对字段进行数据绑定。只有属性。

这应该有效:

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

    public Process Process { get; set; }
}
于 2013-04-23T02:58:39.187 回答
1

1)我无法复制这个问题,你确定有一个正在运行的 chrome 进程吗?: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>

或者更好的是,您重新模板组合框以包含文本块并使用组合框的 hasitems 属性值绑定其可见性(当然您需要使用 BoolToVis 转换器)

3)在填充后将此代码添加到vm构造函数中

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

4)在vm中添加新的repopulate方法并存储当前选中的item,填充,检查是否存在,重新选中item

    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];
            }
        }
    }

注意:
当我尝试上面的代码并对其进行调试时,我不确定要检查什么属性来验证实例的存在,因为我的 chrome 进程列表不断变化。但基本上这就是你能做的

于 2013-04-23T03:26:53.617 回答