我正在WPF中创建一个自定义控件,其中包含一个文本框,图像按钮和一个组合框。我能够使所有内容正确地进行布局,并且所有绑定都可用于除组合框的SelectedItem之外的所有内容。
这是自定义控制代码:
public class GelPakPickerOverlay : Border
{
public static readonly DependencyProperty SelectedGelPakProperty =
DependencyProperty.Register(
"SelectedGelPak",
typeof(object),
typeof(GelPakPickerOverlay),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty LocationProperty =
DependencyProperty.Register(
"Location",
typeof(string),
typeof(GelPakPickerOverlay),
new FrameworkPropertyMetadata(string.Empty, OnLocationChanged));
public static readonly DependencyProperty GelPakSourceProperty =
DependencyProperty.Register(
"GelPakSource",
typeof(IEnumerable),
typeof(GelPakPickerOverlay),
new FrameworkPropertyMetadata(null, OnGelPakSourceChanged));
public static readonly DependencyProperty SaveCommandProperty =
DependencyProperty.Register(
"SaveCommand",
typeof(ICommand),
typeof(GelPakPickerOverlay),
new FrameworkPropertyMetadata(null, OnSaveCommandChanged));
private static ComboBox gpSelector;
private static TextBox gpLocation;
private static Button saveButton;
public GelPakPickerOverlay()
{
Height = 98;
gpSelector = new ComboBox();
gpSelector.Width = 100;
gpSelector.Margin = new Thickness(10);
gpSelector.HorizontalAlignment = HorizontalAlignment.Left;
gpSelector.VerticalAlignment = VerticalAlignment.Center;
Grid grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition());
ColumnDefinition def = new ColumnDefinition();
def.Width = new GridLength(40);
grid.ColumnDefinitions.Add(def);
gpLocation = new TextBox();
gpLocation.Style = (Style) FindResource("TextBoxStyleBase");
gpLocation.Width = 70;
gpLocation.Margin = new Thickness(10);
gpLocation.HorizontalAlignment = HorizontalAlignment.Left;
gpLocation.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(gpLocation, 0);
saveButton = new Button();
saveButton.Style = (Style) FindResource("SaveButton");
saveButton.Margin = new Thickness(0, 10, 10, 10);
saveButton.HorizontalAlignment = HorizontalAlignment.Center;
Grid.SetColumn(saveButton, 1);
grid.Children.Add(gpLocation);
grid.Children.Add(saveButton);
StackPanel mainChild = new StackPanel();
mainChild.Orientation = Orientation.Vertical;
mainChild.Children.Add(gpSelector);
mainChild.Children.Add(grid);
Child = mainChild;
}
public object SelectedGelPak
{
get { return GetValue(SelectedGelPakProperty); }
set { SetValue(SelectedGelPakProperty, value); }
}
public string Location
{
get { return GetValue(LocationProperty).ToString(); }
set { SetValue(LocationProperty, value); }
}
public IEnumerable GelPakSource
{
get { return (IEnumerable) GetValue(GelPakSourceProperty); }
set { SetValue(GelPakSourceProperty, value); }
}
public ICommand SaveCommand
{
get { return (ICommand) GetValue(SaveCommandProperty); }
set { SetValue(SaveCommandProperty, value); }
}
private static void OnLocationChanged(
DependencyObject source, DependencyPropertyChangedEventArgs e)
{
if (gpLocation != null)
{
gpLocation.Text = e.NewValue.ToString();
}
}
private static void OnGelPakSourceChanged(
DependencyObject source, DependencyPropertyChangedEventArgs e)
{
if (gpSelector != null)
{
gpSelector.ItemsSource = (IEnumerable) e.NewValue;
}
}
private static void OnSaveCommandChanged(
DependencyObject source, DependencyPropertyChangedEventArgs e)
{
if (saveButton != null)
{
saveButton.Command = (ICommand) e.NewValue;
}
}
}
这是在主窗口中引用它的方式:
<ctl:GelPakPickerOverlay
Width="132"
DockPanel.Dock="Right"
VerticalAlignment="Bottom"
Background="{StaticResource primaryBrush}"
BorderBrush="{StaticResource accentBrushOne}"
BorderThickness="2,2,0,0"
Visibility="{
Binding GelPakPickerViewModel.IsPickerVisible,
Converter={StaticResource BoolToHiddenVisConverter},
FallbackValue=Visible}"
GelPakSource="{Binding GelPakPickerViewModel.GelPakList}"
SelectedGelPak="{Binding GelPakPickerViewModel.SelectedGelPak}"
Location="{Binding GelPakPickerViewModel.GelPakLocation, UpdateSourceTrigger=LostFocus}"
SaveCommand="{Binding GelPakPickerViewModel.UpdateGpDataCommand}"/>
该窗口的数据上下文是MainWindowViewModel,它具有GelPakPickerViewModel属性,所有绑定都已连接到该属性。 “位置”,“ GelPakSource”和“ SaveCommand”属性都可以正常工作,并将所有内容按我期望的方式路由到GelPakPickerViewModel。但是,当您从组合框中选择任何内容时,它实际上永远不会进入GelPakViewModels SelectedGelPak属性(属于GelPak类型)中。
这里发生了什么?有人对解决此问题有任何建议吗?!
编辑:我将属性更改的事件侦听器添加到SelectedGelPakProperty,如下所示:
public static readonly DependencyProperty SelectedGelPakProperty =
DependencyProperty.Register(
"SelectedGelPak",
typeof(object),
typeof(GelPakPickerOverlay),
new FrameworkPropertyMetadata(null, OnSelectedGelPakChanged));
........
private static void OnSelectedGelPakChanged(
DependencyObject source, DependencyPropertyChangedEventArgs e)
{
if (gpLocation != null)
{
gpSelector.SelectedItem = e.NewValue;
}
}
但这实际上并不会改变视图模型中的SelectedGelPak对象。
最佳答案
您正在侦听ViewModel属性的更改,但这只是数据流动的方式之一。您需要在组合中聆听视图中的更改。
为此,请订阅其SelectionChanged
事件,如下所示:
gpSelector = new ComboBox();
gpSelector.Width = 100;
gpSelector.Margin = new Thickness(10);
gpSelector.HorizontalAlignment = HorizontalAlignment.Left;
gpSelector.VerticalAlignment = VerticalAlignment.Center;
gpSelector.SelectionChanged += OnGpSelectorSelectionChanged;
然后在事件处理程序中,相应地更改DependencyProperty的值:
private void OnGpSelectorSelectionChanged(object sender, SelectionChangedEventArgs e)
{
SetCurrentValue(SelectedGelPakProperty, gpSelector.SelectedItem);
}
这样,您将支持ViewModel和Control之间的双向通信。