首页 > 解决方案 > WPF将用户控件属性绑定到主窗口

问题描述

我正在制作自定义日期和时间用户控件,但遇到了让绑定工作的问题。我认为一切都在用户控制方面工作?但不是在窗边。当您单击按钮时,我的小测试设置应该使用控件上选择的日期和时间来更新窗口的标题。目前它没有更新新的日期。如果我在 's setter 上设置断点,myDate当我更改日期时它不会被调用。如何正确绑定到用户控件?

用户控件 xaml

<UserControl x:Class="DateTimeCntrl.DateTimeControl"
             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:local="clr-namespace:DateTimeCntrl"
             mc:Ignorable="d" 
             d:DesignHeight="32" d:DesignWidth="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <ComboBox Grid.Column="0" 
                  x:Name="cbMonth"
                  SelectionChanged="cb_SelectionChanged"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value"/>
        <ComboBox Grid.Column="1" 
                  x:Name="cbDay"
                  SelectionChanged="cb_SelectionChanged"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value"/>
        <ComboBox Grid.Column="2" 
                  x:Name="cbYear"
                  SelectionChanged="cb_SelectionChanged"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value"/>
        <ComboBox Grid.Column="3" 
                  x:Name="cbHour"
                  SelectionChanged="cb_SelectionChanged"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value"/>
        <ComboBox Grid.Column="4" 
                  x:Name="cbMinute"
                  SelectionChanged="cb_SelectionChanged"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value"/>
        <ComboBox Grid.Column="5" 
                  x:Name="cbAmPm"
                  SelectionChanged="cb_SelectionChanged"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value"/>
    </Grid>
</UserControl>

后面的用户控制代码

public partial class DateTimeControl : UserControl {


        public static readonly DependencyProperty SetDateProperty = DependencyProperty.Register("Date", typeof(DateTime), typeof(DateTimeControl), new PropertyMetadata(DateTime.Now, new PropertyChangedCallback(OnDateChanged)));
        
        public DateTime Date {
            get { return (DateTime)GetValue(SetDateProperty); }
            set { SetValue(SetDateProperty, value); }
        }
        
        public int Month { get { return cbMonth.SelectedValue == null ? 1 : (int)cbMonth.SelectedValue; } }
        public int Day { get { return cbDay.SelectedValue == null ? 1 : (int)cbDay.SelectedValue; } }
        public int Year { get { return cbYear.SelectedValue == null ? 1999 : (int)cbYear.SelectedValue; } }
        public int Hour { get { return cbHour.SelectedValue == null ? 1 : (int)cbHour.SelectedValue; } }
        public int Minute { get { return cbMinute.SelectedValue == null ? 1 : (int)cbMinute.SelectedValue; } }
        public int AmPm { get { return cbAmPm.SelectedValue == null ? 1 : (int)cbAmPm.SelectedValue; } }

        private static void OnDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {

        }

        private void OnDateChanged(DependencyPropertyChangedEventArgs e) {
            DateTime now = (DateTime)e.NewValue;
            cbMonth.SelectedValue = now.Month;
            cbDay.SelectedValue = now.Day;
            cbYear.SelectedValue = now.Year;
            cbHour.SelectedValue = now.Hour > 12 ? now.Hour - 12 : now.Hour;
            cbMinute.SelectedValue = now.Minute;
            cbAmPm.SelectedValue = now.Hour > 12 ? 2 : 1;
        }

        public DateTimeControl() {
            InitializeComponent();
            //DataContext = this;

            DateTime now = DateTime.Now;

            //Months
            for(int i = 1; i < 13; i++) {
                string m = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(i);
                cbMonth.Items.Add(new KeyValuePair<string, int>(m, i));
            }
            cbMonth.SelectedValue = now.Month;

            //Days
            for(int i = 1; i < 32; i++) {
                string d;
                if (i < 10)
                    d = "0" + i.ToString();
                else
                    d = i.ToString();

                cbDay.Items.Add(new KeyValuePair<string, int>(d, i));
            }
            cbDay.SelectedValue = now.Day;

            //Years
            for(int i = DateTime.Now.Year; i > DateTime.Now.Year - 10; i--) {
                cbYear.Items.Add(new KeyValuePair<string, int>(i.ToString(), i));
            }
            cbYear.SelectedValue = now.Year;

            //Hours
            for(int i = 1; i < 13; i++) {
                cbHour.Items.Add(new KeyValuePair<string, int>(i.ToString(), i));
            }
            cbHour.SelectedValue = now.Hour > 12 ? now.Hour - 12 : now.Hour;


            //Minutes
            for (int i = 0; i < 60; i++) {
                string m;
                if (i < 10)
                    m = "0" + i.ToString();
                else
                    m = i.ToString();
                cbMinute.Items.Add(new KeyValuePair<string, int>(m, i));
            }
            cbMinute.SelectedValue = now.Minute;

            //AM PM
            cbAmPm.Items.Add(new KeyValuePair<string, int>("Am", 1));
            cbAmPm.Items.Add(new KeyValuePair<string, int>("Pm", 2));
            cbAmPm.SelectedValue = now.Hour > 12 ? 2 : 1;

        }

        private void updateTime() {

            Date = new DateTime(Year, Month, Day, Hour + AmPm == 2 ? 12 : 0, Minute, 0);
        }

        private void cb_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            updateTime();
        }
    }

主窗口 xaml

<Window x:Class="DateTimeCntrl.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:DateTimeCntrl"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <local:DateTimeControl Date="{Binding myDate}"/>

        <Button Grid.Row="1" Click="Button_Click">click me</Button>
    </Grid>
</Window>

主窗口 xaml

public partial class MainWindow : Window {

        MainViewModel viewmodel;

        public MainWindow() {
            InitializeComponent();
            DataContext = viewmodel = new MainViewModel();
        }

        private void Button_Click(object sender, RoutedEventArgs e) {
            Title = viewmodel.myDate.ToString();
        }
    }

主窗口视图模型

public class MainViewModel : BaseViewModel {
        private DateTime mydate;
        public DateTime myDate {
            get {
                return mydate;
            }
            set {
                mydate = value;
                RaisePropertyChanged("myDate");
            }
        }
    }

标签: c#wpfxaml

解决方案


Use the TwoWay binding mode Date="{Binding myDate, Mode=TwoWay}" in Window xaml while binding to dependency property.

<local:DateTimeControl Date="{Binding myDate, Mode=TwoWay}"/>

推荐阅读