bwoogie
bwoogie

Reputation: 4427

WPF Binding Usercontrol Property to Main Window

I'm making a custom date and time usercontrol, but running into a problem getting the binding to work. I think everything is working on the usercontrol side?. But not on the window side. My little test setup should update the window's title with the date and time selected on the control when you click a button. Currently it's not updating the new date. If I set a breakpoint on myDate's setter it doesn't get called when I change the date. How do I correctly bind to a usercontrol?

Usercontrol 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>

Usercontrol code behind

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();
        }
    }

Main Window 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>

Main 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();
        }
    }

Main Window View Model

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

Upvotes: 1

Views: 1319

Answers (1)

user1672994
user1672994

Reputation: 10839

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}"/>

Upvotes: 1

Related Questions