无需更改 SelectedItem 的 MVVM 可编辑组合框
MVVM Editable ComboBox without changing the SelectedItem
我和这位用户的要求完全一样:.
我试过接受的答案:
"Bind a property like "EditedServerName" to Combobox.Text. When the
"EditedServerName" is changed you can set the value to the
"ServerName" of your SelectedServer."
但它不起作用,因为当我尝试拦截“EditedServerName”时,“SelectedServer”为空。我相信这是因为控件试图在集合中搜索正在编辑的“ServerName”,但显然无法检索元素。当我开始编辑时,这一点非常清楚,带有“ServerID”的文本块立即变空。
XAML:
<ComboBox IsEditable= "True"
ItemsSource= "{Binding Servers}"
DisplayMemberPath= "ServerName"
SelectedItem="{Binding SelectedServer}"
Text= "{Binding EditedServerName, UpdateSourceTrigger=LostFocus}" />
<TextBlock Text="{Binding SelectedServer.ServerID}"/>
视图模型:
public List<Server> Servers { get; set; }
public Server SelectedServer { get; set; }
private string editedServerName;
public string EditedServerName
{
get { return editedServerName; }
set
{
editedServerName = value;
SelectedServer.ServerName = value;
}
}
public MainViewModel()
{
Servers = new List<Server>();
Servers.Add(new Server { ServerID = 0, ServerName = "Local" });
Servers.Add(new Server { ServerID = 1, ServerName = "Remote" });
}
我知道我可以将“SelectedServer”临时存储在另一个对象上,但如果可能,我希望有更好的周转时间。
几件事:
您的 MainViewModel
没有正确使用 INotifyPropertyChanged
接口,建议将数据绑定回视图。这就是您当前发布的代码 UI 没有变化的原因。
你说的对,一旦EditedServerName
改变,SelectedServer
就会变成null,但是有一点1,也快到那个地步了。即使我们修改代码以适应数据绑定,SelectedServer
属性 也不会处理 null.
考虑到这一点,如果我们修改代码以适应以上几点,代码可能如下所示:
下面的代码有助于通知视图我们的模型/视图模型的任何更改
public class BaseNotifier : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
这是我们更新后的模型的样子。请注意 BaseNotifier
中定义的 OnPropertyChanged
的使用,因为这将使用新服务器名称
更新视图
public class Server : BaseNotifier
{
private string _serverName;
public string ServerName
{
get { return _serverName; }
set
{
_serverName = value;
OnPropertyChanged();
}
}
private int _serverID;
public int ServerID
{
get { return _serverID; }
set
{
_serverID = value;
OnPropertyChanged();
}
}
}
这就是 ViewModel 现在的样子。对于 ViewModel,使用 ObservableCollection
而不是 List
以允许在插入数据时自动更新视图。您还会注意到,代码会检查 SelectedServer 和 EditedServerName 中的空值,这应该可以处理您的原始问题。
public class MainViewModel : BaseNotifier
{
private string editedServerName;
private Server selectedServer = null;
public ObservableCollection<Server> Servers { get; set; }
public Server SelectedServer
{
get { return selectedServer; }
set
{
if (value != null)
{
selectedServer = value;
OnPropertyChanged();
}
}
}
public string EditedServerName
{
get { return editedServerName; }
set
{
editedServerName = value;
if (SelectedServer != null)
{
SelectedServer.ServerName = value;
}
OnPropertyChanged();
}
}
public MainViewModel()
{
Servers = new ObservableCollection<Server>();
Servers.Add(new Server { ServerID = 0, ServerName = "Local" });
Servers.Add(new Server { ServerID = 1, ServerName = "Remote" });
}
}
我和这位用户的要求完全一样:
我试过接受的答案:
"Bind a property like "EditedServerName" to Combobox.Text. When the "EditedServerName" is changed you can set the value to the "ServerName" of your SelectedServer."
但它不起作用,因为当我尝试拦截“EditedServerName”时,“SelectedServer”为空。我相信这是因为控件试图在集合中搜索正在编辑的“ServerName”,但显然无法检索元素。当我开始编辑时,这一点非常清楚,带有“ServerID”的文本块立即变空。
XAML:
<ComboBox IsEditable= "True"
ItemsSource= "{Binding Servers}"
DisplayMemberPath= "ServerName"
SelectedItem="{Binding SelectedServer}"
Text= "{Binding EditedServerName, UpdateSourceTrigger=LostFocus}" />
<TextBlock Text="{Binding SelectedServer.ServerID}"/>
视图模型:
public List<Server> Servers { get; set; }
public Server SelectedServer { get; set; }
private string editedServerName;
public string EditedServerName
{
get { return editedServerName; }
set
{
editedServerName = value;
SelectedServer.ServerName = value;
}
}
public MainViewModel()
{
Servers = new List<Server>();
Servers.Add(new Server { ServerID = 0, ServerName = "Local" });
Servers.Add(new Server { ServerID = 1, ServerName = "Remote" });
}
我知道我可以将“SelectedServer”临时存储在另一个对象上,但如果可能,我希望有更好的周转时间。
几件事:
您的
MainViewModel
没有正确使用INotifyPropertyChanged
接口,建议将数据绑定回视图。这就是您当前发布的代码 UI 没有变化的原因。你说的对,一旦
EditedServerName
改变,SelectedServer
就会变成null,但是有一点1,也快到那个地步了。即使我们修改代码以适应数据绑定,SelectedServer
属性 也不会处理 null.
考虑到这一点,如果我们修改代码以适应以上几点,代码可能如下所示:
下面的代码有助于通知视图我们的模型/视图模型的任何更改
public class BaseNotifier : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
这是我们更新后的模型的样子。请注意 BaseNotifier
中定义的 OnPropertyChanged
的使用,因为这将使用新服务器名称
public class Server : BaseNotifier
{
private string _serverName;
public string ServerName
{
get { return _serverName; }
set
{
_serverName = value;
OnPropertyChanged();
}
}
private int _serverID;
public int ServerID
{
get { return _serverID; }
set
{
_serverID = value;
OnPropertyChanged();
}
}
}
这就是 ViewModel 现在的样子。对于 ViewModel,使用 ObservableCollection
而不是 List
以允许在插入数据时自动更新视图。您还会注意到,代码会检查 SelectedServer 和 EditedServerName 中的空值,这应该可以处理您的原始问题。
public class MainViewModel : BaseNotifier
{
private string editedServerName;
private Server selectedServer = null;
public ObservableCollection<Server> Servers { get; set; }
public Server SelectedServer
{
get { return selectedServer; }
set
{
if (value != null)
{
selectedServer = value;
OnPropertyChanged();
}
}
}
public string EditedServerName
{
get { return editedServerName; }
set
{
editedServerName = value;
if (SelectedServer != null)
{
SelectedServer.ServerName = value;
}
OnPropertyChanged();
}
}
public MainViewModel()
{
Servers = new ObservableCollection<Server>();
Servers.Add(new Server { ServerID = 0, ServerName = "Local" });
Servers.Add(new Server { ServerID = 1, ServerName = "Remote" });
}
}