WPF TwoWay绑定不适用于模板中的CustomControl

时间:2017-12-19 14:53:21

标签: c# wpf xaml templates binding

我的自定义控件存在一些问题 - 当我在模板中使用时,双向绑定无法正常工作。 所以我创建了模板xaml

<ResourceDictionary 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:WpfApp1"
                xmlns:controls="clr-namespace:GUIControls;assembly=GUIControls"
                >

  <ResourceDictionary 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:WpfApp1"
                xmlns:controls="clr-namespace:GUIControls;assembly=GUIControls"
                >

<ControlTemplate x:Key="YParamCombo" TargetType="ContentControl">
    <controls:ParamCombo Header="MY CONTROL TEMPLATE"
    Items="{Binding Items}"
    PCValue="{Binding Codes[MY_CONTROL_TEMPLATE], Mode=TwoWay}"
    Required="True"
    MultiSelect="False"/>
</ControlTemplate>

<ControlTemplate x:Key="YComboBox" TargetType="ContentControl">
    <ComboBox       DisplayMemberPath="Name" 
    StaysOpenOnEdit="True" 
    ItemsSource="{Binding Items}"
    SelectedValue="{Binding Codes[STANDARD_TEMPLATE], Mode=TwoWay}"
    SelectedValuePath="Code"/> 
</ControlTemplate>    

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
xmlns:controls="clr-namespace:GUIControls;assembly=GUIControls"
Title="MainWindow" Height="250" Width="525">

<Grid Margin="0,0,0,-1">
    <Button Margin="62,162,299,4" Content="Show Codes-1" Click="Button_Click2"></Button>
    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <HeaderedContentControl Header="STANDARD CONTROL XAML" >
            <ComboBox DisplayMemberPath="Name" 
                StaysOpenOnEdit="True" 
                ItemsSource="{Binding Items}"
                SelectedValue="{Binding Codes[STANDARD_XAML]}"
                SelectedValuePath="Code"/>
        </HeaderedContentControl>
        <HeaderedContentControl Header="STANDARD CONTROL TEMPLATE" >
            <ContentControl Height="23" Template="{StaticResource YComboBox}"/>
        </HeaderedContentControl>
        <ContentControl Height="44" Template="{StaticResource YParamCombo}">
        </ContentControl>
        <controls:ParamCombo Header="MY CONTROL XAML"
            Items="{Binding Items}"
            PCValue="{Binding Codes[MYCONTROL_XAML], Mode=TwoWay}"
            Required="True"
            MultiSelect="False"/>
    </StackPanel>
</Grid>

CS

using System.Linq;
using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            DataContext = new WModel();
            InitializeComponent();
        }
        private WModel vm { get { return (DataContext as WModel); } }
        private void Button_Click2(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(string.Join(";", vm.Codes._codes.Select(x => x.Key + "=" + x.Value).ToArray()));
        }
    }
}

using GUIControls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace WpfApp1
{
    public class WModel
    {
        public WModel()
        {
            Codes = new CodesClass();
        }
        public string Caption { get; set; }
        public ObservableCollection<Dict> Items
        {
            get
            {
                return new ObservableCollection<Dict>()
                {
                    new Dict(){ Name = "Name1",  Code = "Code1"  } ,
                    new Dict(){ Name = "Name2",  Code = "Code2"  }
                };
            }
        }
        public CodesClass Codes { get; set; }
    }
    public class Dict : IDict
    {
        public string Name { get; set; }
        public string Code { get; set; }
    }
    public class CodesClass
    {
        public Dictionary<string, object> _codes;
        public CodesClass()
        {
            _codes = new Dictionary<string, object>();
        }
        public object this[string param]
        {
            get
            {
                if (_codes.ContainsKey(param))
                    return _codes[param];
                else
                    return null;//  "I have no " + param;
            }
            set
            {
                _codes[param] = value;
            }
        }
    }
}

当我运行app并选择所有4个组合框并按下按钮时,我可以看到一个组合框中的双向绑定(模板中声明的自定义控件)不起作用

---------------------------

---------------------------
STANDARD_XAML=Code2;STANDARD_TEMPLATE=Code2;MYCONTROL_XAML=Code2
---------------------------
ОК   
---------------------------

来自控件的一些代码

        public static readonly DependencyProperty PCValueProperty =
         DependencyProperty.Register("PCValue", typeof(string), typeof(ParamCombo),
             new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPCValuePropertyChanged)));
    //new PropertyMetadata(new PropertyChangedCallback(OnValuePropertyChanged)));, new PropertyChangedCallback(OnPCValuePropertyChanged))
    #endregion

    private static void OnPCValuePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ParamCombo paramCombo = (ParamCombo)sender;
        paramCombo.UpdateSelected((e.NewValue == null) ? "" : e.NewValue.ToString());
    }

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我在自定义控件模板中的组合中遇到twoway绑定问题,解决方法是在自定义控件中覆盖OnApplyTemplate,使用Template.FindName获取组合,获取组合的DataContex对象并在其中引发PropertyChanged绑定属性的DataContext对象。我的问题是在加载窗口时更新组合。