我正在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之间的双向通信。

07-24 21:34