我用一个DependencyProperty做了一个UserControl,我想绑定2种方式。但不知何故,这是行不通的。当属性更改时,“城市”属性从不会在AddressViewModel中设置。WPF用户控件 - 双向绑定不起作用
这是我的用户: XAML:
<UserControl x:Class="EasyInvoice.UI.CityPicker"
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"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="300"
DataContext="{Binding CityList, Source={StaticResource Locator}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox IsReadOnly="True" Margin="3" Text="{Binding SelectedCity.PostalCode, Mode=OneWay}" Background="#EEE" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
<ComboBox Margin="3" Grid.Column="1" ItemsSource="{Binding Path=Cities}" DisplayMemberPath="CityName" SelectedItem="{Binding SelectedCity}"/>
</Grid>
</UserControl>
后面的代码:
using EasyInvoice.UI.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EasyInvoice.UI
{
/// <summary>
/// Interaction logic for CityPicker.xaml
/// </summary>
public partial class CityPicker : UserControl
{
public CityPicker()
{
InitializeComponent();
((CityListViewModel)this.DataContext).PropertyChanged += CityPicker_PropertyChanged;
}
private void CityPicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedCity")
SetCurrentValue(SelectedCityProperty, ((CityListViewModel)this.DataContext).SelectedCity);
}
public static readonly DependencyProperty SelectedCityProperty =
DependencyProperty.Register("SelectedCity", typeof(CityViewModel), typeof(CityPicker),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public CityViewModel SelectedCity
{
get
{
return (CityViewModel)GetValue(SelectedCityProperty);
}
set
{
SetCurrentValue(SelectedCityProperty, value);
}
}
}
}
这是我用这个控制:
<UserControl x:Class="EasyInvoice.UI.NewCustomerView"
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"
mc:Ignorable="d"
Height="135" Width="450"
xmlns:xctk="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
xmlns:einvoice="clr-namespace:EasyInvoice.UI">
<UserControl.Resources>
<Style TargetType="xctk:WatermarkTextBox">
<Setter Property="Margin" Value="3"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<xctk:WatermarkTextBox Grid.ColumnSpan="2" Watermark="Voornaam" Text="{Binding FirstName}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="2" Watermark="Famillienaam" Grid.Column="2" Text="{Binding LastName}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="2" Watermark="Straat" Grid.Row="2" Text="{Binding Address.Street}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="1" Watermark="Huisnummer" Grid.Column="2" Grid.Row="2" Text="{Binding Address.HouseNr}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="1" Watermark="Busnummer" Grid.Column="3" Grid.Row="2" Text="{Binding Address.BusNr}"/>
<einvoice:CityPicker Grid.Row="3" Grid.ColumnSpan="4" SelectedCity="{Binding Address.City, Mode=TwoWay}"/>
<Button Grid.Row="5" Content="Opslaan en sluiten" Grid.ColumnSpan="4" Style="{StaticResource PopupButton}"/>
</Grid>
</UserControl>
这是视图模型为“地址”:
using EasyInvoice.Model;
using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EasyInvoice.UI.ViewModel
{
public class AddressViewModel : ViewModelBase
{
private string _street;
private string _houseNr;
private string _busNr;
private CityViewModel _city;
public AddressViewModel(Address address)
{
LoadAddress(address);
}
public AddressViewModel() : this(new Address()) { }
private Address Address { get; set; }
public string Street
{
get
{
return _street;
}
set
{
if (_street == value)
return;
_street = value;
RaisePropertyChanged("Street");
}
}
public string HouseNr
{
get
{
return _houseNr;
}
set
{
if (_houseNr == value)
return;
_houseNr = value;
RaisePropertyChanged("HouseNr");
}
}
public string BusNr
{
get
{
return _busNr;
}
set
{
if (_busNr == value)
return;
_busNr = value;
RaisePropertyChanged("BusNr");
}
}
public string BusNrParen
{
get
{
return string.Concat("(", BusNr, ")");
}
}
public bool HasBusNr
{
get
{
return !string.IsNullOrWhiteSpace(_busNr);
}
}
public CityViewModel City
{
get
{
return _city;
}
set
{
if (_city == value)
return;
_city = value;
RaisePropertyChanged("City");
}
}
public void LoadAddress(Address address)
{
this.Address = address;
if(address == null)
{
_street = "";
_houseNr = "";
_busNr = "";
_city = new CityViewModel(null);
}
else
{
_street = address.StreetName;
_houseNr = address.HouseNr;
_busNr = address.BusNr;
_city = new CityViewModel(address.City);
}
}
}
}
当我调试,我可以看到,当我改变我的UI特性达到该行:
SetCurrentValue(SelectedCityProperty, ((CityListViewModel)this.DataContext).SelectedCity);
但不知何故,这永远不会被设置:
public CityViewModel City
{
get
{
return _city;
}
set
{
if (_city == value)
return;
_city = value;
RaisePropertyChanged("City");
}
}
另外,我确定viewmodel连接正确,因为我在“HouseNr”设置了一个断点,这个工作正常。
万一没有足够的规定,项目可以在这里找到:https://github.com/SanderDeclerck/EasyInvoice
你的代码不能编译。你的城市选择器控件没有实现'INotifyPropertyChange'它怎么能够订阅这个事件? –
在这里,它编译,我的CityPicker也不使用INotifyPropertyChanged接口,这只是在我的viewmodels(在这种情况下CityListViewModel和AddressViewModel) –