[英]Having problems with WPF Databinding
I have 2 objects, a Customer and a Store. 我有2个对象,一个是客户和一个商店。 There are multiple store locations, each customer has a property called PreferredStoreId (int?) which relates to a Store's Id (int).
有多个商店位置,每个客户都有一个名为PreferredStoreId(int?)的属性,它与商店的Id(int)相关。
In a WPF application I am attempting to build a form that allows a customer to be edited. 在WPF应用程序中,我试图构建一个允许客户编辑的表单。 A combo box exists on this form which is filled with Stores to act as a way of displaying the currently set PreferredStore and a way of changing the preferred store.
此表单上存在一个组合框,其中包含Stores,用作显示当前设置的PreferredStore的方式以及更改首选商店的方式。
My problem is, whilst I can populate the combobox, I cannot get two way binding between the Customer.PreferredId (the object set to the UserControl's datacontext) and the combobox's SelectedItem (a Store Object)'s .Id property. 我的问题是,虽然我可以填充组合框,但我无法在Customer.PreferredId(设置为UserControl的datacontext的对象)和组合框的SelectedItem(商店对象)的.Id属性之间进行双向绑定。
Here Is my XAML to help make sense: 这是我的XAML有助于理解:
<UserControl x:Class="ucCustomerEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:localViewModels="clr-namespace:ViewModels"
xmlns:qc="clr-namespace:QuickConverter;assembly=QuickConverter"
mc:Ignorable="d" d:DesignWidth="750" Height="334">
<UserControl.DataContext>
<localViewModels:CustomerViewModel x:Name="customerViewModel" />
</UserControl.DataContext>
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Height="26" Width="50" Content="Save" Margin="5,10" Click="UserAction_Save" />
<Button Height="26" Width="50" Content="Cancel" Margin="10,10" Click="UserAction_Cancel" />
</StackPanel>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding FirstName}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="First Name:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding LastName}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Last Name:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding EmailAddress}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Email Address:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding PhoneNumber}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Phone Number:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ComboBox Name="cbPreferredStore"
ItemsSource="{Binding Stores}" DisplayMemberPath="DisplayName" Height="23" Margin="10,0,0,0" VerticalAlignment="Top"
HorizontalAlignment="Stretch" Grid.Column="1" SelectedValue="{Binding ElementName=customerViewModel, Path=PreferredStoreId}">
<ComboBox.DataContext>
<localViewModels:StoreListViewModel />
</ComboBox.DataContext>
</ComboBox>
<Label Content="Preferred Store:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding Password}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Password:" Margin="10,0" VerticalAlignment="Top" Height="26" FontWeight="Bold"/>
</Grid>
</StackPanel>
StoreViewModel code: StoreViewModel代码:
ublic class StoreViewModel : BaseViewModel
{
private enum Modes { CREATE, UPDATE }
private Modes _mode;
private Store _store;
public string DisplayName
{
get { return string.Format("{0} ({1})", this._store.LocationName, this._store.Id); }
}
public int Id
{
get { return this._store.Id; }
set
{
this._store.Id = value;
notifyPropertyChanged("Id");
notifyPropertyChanged("DisplayName");
}
}
public string LocationName
{
get { return this._store.LocationName; }
set
{
this._store.LocationName = value;
notifyPropertyChanged("LocationName");
notifyPropertyChanged("DisplayName");
}
}
public string ImageURL
{
get { return this._store.ImageURL; }
set
{
this._store.ImageURL = value;
notifyPropertyChanged("ImageURL");
}
}
public string AddressLine1
{
get { return this._store.AddressLine1; }
set
{
this._store.AddressLine1 = value;
notifyPropertyChanged("AddressLine1");
}
}
public string AddressLine2
{
get { return this._store.AddressLine2; }
set
{
this._store.AddressLine2 = value;
notifyPropertyChanged("AddressLine2");
}
}
public string AddressLine3
{
get { return this._store.AddressLine3; }
set
{
this._store.AddressLine3 = value;
notifyPropertyChanged("AddressLine3");
}
}
public string Suburb
{
get { return this._store.Suburb; }
set
{
this._store.Suburb = value;
notifyPropertyChanged("Suburb");
}
}
public string State
{
get { return this._store.State; }
set
{
this._store.State = value;
notifyPropertyChanged("State");
}
}
public string Postcode
{
get { return this._store.Postcode; }
set
{
this._store.Postcode = value;
notifyPropertyChanged("Postcode");
}
}
public string Country
{
get { return this._store.Country; }
set
{
this._store.Country = value;
notifyPropertyChanged("Country");
}
}
public string PhoneNumber
{
get { return this._store.PhoneNumber; }
set
{
this._store.PhoneNumber = value;
notifyPropertyChanged("PhoneNumber");
}
}
public string EmailAddress
{
get { return this._store.EmailAddress; }
set
{
this._store.EmailAddress = value;
notifyPropertyChanged("EmailAddress");
}
}
public static explicit operator StoreViewModel(EasyDayTea.Store store)
{
return new StoreViewModel(store) { _mode = Modes.UPDATE };
}
public StoreViewModel()
{
_store = new Store();
_mode = Modes.CREATE;
}
public StoreViewModel(Store store)
{
_store = store;
_mode = Modes.UPDATE;
}
public void Cancel()
{
if (_mode == Modes.CREATE)
{
_store = new Store() { };
}
else
{
EasyDayTea.EasyDayTeaClient client = new EasyDayTeaClient();
_store = client.FetchStore(App.AppUserTeaCredental, _store.Id);
client.Close();
}
notifyAll();
}
public void Save()
{
try
{
EasyDayTeaClient client = new EasyDayTeaClient();
if (_mode == Modes.CREATE)
{
client.AddStore(App.AppUserTeaCredental, ImageURL, LocationName, AddressLine1, AddressLine2, AddressLine3, Suburb, State, Postcode, Country, PhoneNumber, EmailAddress);
}
else
{
client.SetStore(App.AppUserTeaCredental, Id, ImageURL, LocationName, AddressLine1, AddressLine2, AddressLine3, Suburb, State, Postcode, Country, PhoneNumber, EmailAddress);
}
client.Close();
MessageBox.Show("Your customer was saved.");
if (_mode == Modes.CREATE)
{
_store = new Store();
notifyAll();
}
else
{
//do nothing.
}
}
catch (Exception ex)
{
MessageBox.Show("There was a problem saving your customer: \r\n" + ex.Message);
}
}
internal void notifyAll()
{
notifyPropertyChanged("Id");
notifyPropertyChanged("LocationName");
notifyPropertyChanged("ImageURL");
notifyPropertyChanged("AddressLine1");
notifyPropertyChanged("AddressLine2");
notifyPropertyChanged("AddressLine3");
notifyPropertyChanged("Suburb");
notifyPropertyChanged("State");
notifyPropertyChanged("Postcode");
notifyPropertyChanged("Country");
notifyPropertyChanged("PhoneNumber");
notifyPropertyChanged("EmailAddress");
notifyPropertyChanged("DisplayName");
}
}
StoreListViewModel Code: StoreListViewModel代码:
public class StoreListViewModel : BaseViewModel
{
private List<StoreViewModel> _stores;
public List<StoreViewModel> Stores
{
get { return this._stores; }
set
{
this._stores = value;
notifyPropertyChanged("Stores");
}
}
public StoreListViewModel()
{
EasyDayTea.EasyDayTeaClient client = new EasyDayTea.EasyDayTeaClient();
_stores = client.GetStores(App.AppUserTeaCredental).Select(s => (StoreViewModel)s).ToList();
client.Close();
}
}
I suppose that PreferredStoreId
property in CustomerViewModel correctly implement the INotifyPropertyChanged
interface. 我想CustomerViewModel中的
PreferredStoreId
属性正确实现了INotifyPropertyChanged
接口。
If it's true, then you need change the SelectedValue to SelectedItem
of your ComboBox, because SelectedItem property returns the entire object which it current selected. 如果这是真的,那么你需要改变的SelectedValue到
SelectedItem
的组合框,因为SelectedItem属性返回其当前选中整个对象。 However, the SelectedValuePath
property and the SelectedValue
uses together as an alternative to the SelectedItem property and as I understand it was not your choice. 但是,
SelectedValuePath
属性和SelectedValue
一起使用作为SelectedItem属性的替代,并且据我所知它不是您的选择。
Also here: 也在这里:
SelectedValue="{Binding ElementName=customerViewModel, Path=PreferredStoreId}"
Not need ElementName, because a CustomerViewModel set the DataContext
assigned by default. 不需要ElementName,因为CustomerViewModel设置默认分配的
DataContext
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.