Tôi có một ComboBox dường như không cập nhật mục Chọn / ChọnValue.
ComboBox ItemSource được liên kết với một thuộc tính trên lớp ViewModel liệt kê một loạt các mục nhập danh bạ RAS dưới dạng CollectionView. Sau đó, tôi đã ràng buộc (tại các thời điểm riêng biệt) cả SelectedItem
hoặc SelectedValue
với một thuộc tính khác của ViewModel. Tôi đã thêm MessageBox vào lệnh lưu để gỡ lỗi các giá trị được đặt bởi cơ sở dữ liệu, nhưng liên kết SelectedItem
/ SelectedValue
không được đặt.
Lớp ViewModel trông giống như thế này:
public ConnectionViewModel
{
private readonly CollectionView _phonebookEntries;
private string _phonebookeEntry;
public CollectionView PhonebookEntries
{
get { return _phonebookEntries; }
}
public string PhonebookEntry
{
get { return _phonebookEntry; }
set
{
if (_phonebookEntry == value) return;
_phonebookEntry = value;
OnPropertyChanged("PhonebookEntry");
}
}
}
Bộ sưu tập _phonebookEntries đang được khởi tạo trong hàm tạo từ một đối tượng kinh doanh. ComboBox XAML trông giống như thế này:
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
Tôi chỉ quan tâm đến giá trị chuỗi thực được hiển thị trong ComboBox, không phải bất kỳ thuộc tính nào khác của đối tượng vì đây là giá trị tôi cần chuyển qua RAS khi tôi muốn tạo kết nối VPN, do đó DisplayMemberPath
và SelectedValuePath
cả hai đều là thuộc tính Tên của ConnectionViewModel. ComboBox được DataTemplate
áp dụng cho ItemsControl
một Cửa sổ mà DataContext đã được đặt thành phiên bản ViewModel.
ComboBox hiển thị danh sách các mục chính xác và tôi có thể chọn một mục trong giao diện người dùng mà không gặp vấn đề gì. Tuy nhiên, khi tôi hiển thị hộp thông báo từ lệnh, thuộc tính PhonebookEntry vẫn có giá trị ban đầu, không phải giá trị được chọn từ ComboBox. Các phiên bản TextBox khác đang cập nhật tốt và hiển thị trong MessageBox.
Tôi còn thiếu gì với databinding ComboBox? Tôi đã thực hiện rất nhiều tìm kiếm và dường như không thể tìm thấy bất cứ điều gì mà tôi đang làm sai.
Đây là hành vi tôi đang thấy, tuy nhiên nó không hoạt động vì một số lý do trong bối cảnh cụ thể của tôi.
Tôi có MainWindowViewModel có CollectionView
ConnectionViewModels. Trong mã tệp MainWindowView.xaml phía sau, tôi đặt DataContext thành MainWindowViewModel. MainWindowView.xaml có ItemsControl
ràng buộc với bộ sưu tập ConnectionViewModels. Tôi có một DataTemplate chứa ComboBox cũng như một số TextBox khác. Các TextBox được liên kết trực tiếp với các thuộc tính của ConnectionViewModel bằng cách sử dụng Text="{Binding Path=ConnectionName}"
.
public class ConnectionViewModel : ViewModelBase
{
public string Name { get; set; }
public string Password { get; set; }
}
public class MainWindowViewModel : ViewModelBase
{
// List<ConnectionViewModel>...
public CollectionView Connections { get; set; }
}
Mã XAML phía sau:
public partial class Window1
{
public Window1()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
Sau đó, XAML:
<DataTemplate x:Key="listTemplate">
<Grid>
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
<TextBox Text="{Binding Path=Password}" />
</Grid>
</DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Connections}"
ItemTemplate="{StaticResource listTemplate}" />
Tất cả các TextBox đều liên kết chính xác và dữ liệu di chuyển giữa chúng và ViewModel mà không gặp sự cố. Đó chỉ là ComboBox không hoạt động.
Bạn đúng trong giả định của mình về lớp PhonebookEntry.
Giả định mà tôi đưa ra là DataContext được sử dụng bởi DataTemplate của tôi được đặt tự động thông qua hệ thống phân cấp ràng buộc, do đó tôi không phải đặt nó rõ ràng cho từng mục trong ItemsControl
. Điều đó có vẻ hơi ngớ ngẩn với tôi.
Dưới đây là một triển khai thử nghiệm thể hiện vấn đề, dựa trên ví dụ trên.
XAML:
<Window x:Class="WpfApplication7.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="itemTemplate">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=Name}" Width="50" />
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}"
Width="200"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Path=Connections}"
ItemTemplate="{StaticResource itemTemplate}" />
</Grid>
</Window>
Các mã sau :
namespace WpfApplication7
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
public class PhoneBookEntry
{
public string Name { get; set; }
public PhoneBookEntry(string name)
{
Name = name;
}
}
public class ConnectionViewModel : INotifyPropertyChanged
{
private string _name;
public ConnectionViewModel(string name)
{
_name = name;
IList<PhoneBookEntry> list = new List<PhoneBookEntry>
{
new PhoneBookEntry("test"),
new PhoneBookEntry("test2")
};
_phonebookEntries = new CollectionView(list);
}
private readonly CollectionView _phonebookEntries;
private string _phonebookEntry;
public CollectionView PhonebookEntries
{
get { return _phonebookEntries; }
}
public string PhonebookEntry
{
get { return _phonebookEntry; }
set
{
if (_phonebookEntry == value) return;
_phonebookEntry = value;
OnPropertyChanged("PhonebookEntry");
}
}
public string Name
{
get { return _name; }
set
{
if (_name == value) return;
_name = value;
OnPropertyChanged("Name");
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class MainWindowViewModel
{
private readonly CollectionView _connections;
public MainWindowViewModel()
{
IList<ConnectionViewModel> connections = new List<ConnectionViewModel>
{
new ConnectionViewModel("First"),
new ConnectionViewModel("Second"),
new ConnectionViewModel("Third")
};
_connections = new CollectionView(connections);
}
public CollectionView Connections
{
get { return _connections; }
}
}
}
Nếu bạn chạy ví dụ đó, bạn sẽ có hành vi mà tôi đang nói đến. TextBox cập nhật ràng buộc của nó khi bạn chỉnh sửa nó, nhưng ComboBox thì không. Rất khó hiểu khi thực sự là điều duy nhất tôi đã làm là giới thiệu một phụ huynh ViewModel.
Tôi hiện đang chuyển dạ theo ấn tượng rằng một mục được liên kết với con của DataContext có con đó là DataContext của nó. Tôi không thể tìm thấy bất kỳ tài liệu nào xóa cái này bằng cách này hay cách khác.
I E,
Window -> DataContext = MainWindowViewModel
..Items -> Bound to DataContext.PhonebookEntries
.... Item -> DataContext = PhonebookEntry (liên kết ngầm)
Tôi không biết nếu điều đó giải thích giả định của tôi tốt hơn (?).
Để xác nhận giả định của tôi, hãy thay đổi ràng buộc của TextBox thành
<TextBox Text="{Binding Mode=OneWay}" Width="50" />
Và điều này sẽ hiển thị gốc liên kết TextBox (mà tôi đang so sánh với DataContext) là phiên bản ConnectionViewModel.
<
T>
và trong getter thuộc tính bằng cách sử dụng _list.AsReadOnly () tương tự như cách bạn đã đề cập. Nó hoạt động như tôi đã hy vọng phương pháp ban đầu sẽ có. Ngoài ra, tôi nghĩ rằng trong khi ràng buộc ItemSource hoạt động tốt, tôi có thể chỉ sử dụng thuộc tính Hiện tại trong ViewModel để truy cập vào mục đã chọn trong ComboBox. Tuy nhiên, nó không có cảm giác tự nhiên như ràng buộc thuộc tính ComboBoxes ChọnValue / chọnItem.