[英]ComboBox Binding to Custom ViewModel
我正在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下拉列表中看到很多值,但是它们都是空的。 我想在ComboBox中显示BrowserInstance.Name
属性,并在选择一个项目时检索BrowserInstance.Process
值。
2)启动应用程序时,将检查当前正在运行的浏览器进程,以填充ComboBox。 如果找不到正在运行的实例,如何在ComboBox中显示一条消息,如“找不到实例!”?
3)如果在应用程序统计信息中找到一个或多个浏览器实例,默认情况下如何选择第一个?
4)将使用“重新填充”按钮来重新检查用户正在运行的浏览器实例。 假设先前选择的实例仍在运行...如何保持选择的实例? 如果先前选择的实例不再运行,那么默认情况下如何再次选择第一个实例?
非常感谢!
编辑:这是我的当前代码
主窗口:
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");
}
BrowserInstance是具有两个公共字段的简单结构:
WPF不支持将数据绑定到字段。 仅属性。
这应该工作:
public class BrowserInstance
{
public string Name { get; set; }
public Process Process { get; set; }
}
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中,并存储当前选择的项目,填充,检查是否存在,重新选择项目
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];
}
}
}
注意:
我不确定在尝试上面的代码并对其进行调试时要检查哪个属性以验证实例becoz的存在,我的镶边进程列表不断更改。 但基本上那就是你可以做的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.