无需更改 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”临时存储在另一个对象上,但如果可能,我希望有更好的周转时间。

几件事:

  1. 您的 MainViewModel 没有正确使用 INotifyPropertyChanged 接口,建议将数据绑定回视图。这就是您当前发布的代码 UI 没有变化的原因。

  2. 你说的对,一旦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" });
    }
}