2009-11-25 21 views
15

मैं टूलकिट के डेटपिकर का उपरोक्त उपयोग कर रहा हूं लेकिन मैं इसे केवल महीने और साल के चयन तक सीमित करना चाहता हूं, क्योंकि इस स्थिति में उपयोगकर्ता सही तारीख के बारे में नहीं जानते या परवाह नहीं करते हैं जाहिर है, डेटाटाइम प्रारूप में संग्रहीत डेटा के साथ दिन संग्रहित किया जाएगा लेकिन इससे मुझे कोई चिंता नहीं है। क्या इसे बांधने का कोई आसान तरीका है?डब्ल्यूपीएफ टूलकिट डेटपिकर महीना/वर्ष केवल

धन्यवाद

उत्तर

9

आप के बजाय कैलेंडर नियंत्रण का उपयोग कर सकते हैं तो आप इस codebehind

Private Sub _calendar_DisplayModeChanged(ByVal sender As System.Object, ByVal e As Microsoft.Windows.Controls.CalendarModeChangedEventArgs) 

    If _calendar.DisplayMode = Microsoft.Windows.Controls.CalendarMode.Month Then 
     _calendar.DisplayMode = Microsoft.Windows.Controls.CalendarMode.Year 
    End If 

End Sub 
+7

यह मेरे लिए काम नहीं किया। यह चयनित दिनांक कभी नहीं आबादी। डिस्प्लेडेट विश्वसनीय नहीं था क्योंकि यह बदल सकता था क्योंकि उपयोगकर्ता ने अपने माउस को दूसरे बटन पर क्लिक करने के लिए चारों ओर ले जाया था। – JDPeckham

5

साथ

<toolkit:Calendar x:Name="_calendar" DisplayModeChanged="_calendar_DisplayModeChanged" DisplayMode="Year" /> 

कर सकता है हाल ही में मैं चयन करने के लिए विकल्प के साथ कैलेंडर के लिए एक विशिष्ट आवश्यकता थी केवल महीने और साल। तो मेरे पास wpf datepicker के लिए कस्टम प्रारूप के बारे में पिछली पोस्ट है, लेकिन इस मामले में हमें थोड़ा मुश्किल जवाब देने की आवश्यकता है। एक बार जब आप यह पहले से ही कर दिया है

public class DatePickerCo : DatePicker 

: सबसे पहले आप इस तरह एक विशिष्ट नियंत्रण बनाने की जरूरत है। एक और पोस्ट मौजूद न होने पर किसी और को, मुझे लगता है कि इस पद के लिए यूआरएल rememberer नहीं है, लेकिन वैसे भी, लगता है कि तुम सिर्फ इस तरह OnCalendarOpened विधि अधिलेखित करने के लिए की जरूरत है:


protected override void OnCalendarOpened(RoutedEventArgs e) 
     { 
      var popup = this.Template.FindName(
       "PART_Popup", this) as Popup; 
      if (popup != null && popup.Child is System.Windows.Controls.Calendar) 
      { 
       ((System.Windows.Controls.Calendar)popup.Child).DisplayMode = CalendarMode.Year; 
      } 

      ((System.Windows.Controls.Calendar)popup.Child).DisplayModeChanged += new EventHandler(DatePickerCo_DisplayModeChanged); 
     } 

सूचना हम साथ एक अंतिम पंक्ति जोड़ देते हैं घटना के लिए हैंडलर DisplayModeChanged। यह अगले चरणों के लिए वास्तव में महत्वपूर्ण है। ठीक है तो अगले कदम के पहले तुम इतनी कारण thats समारोह GetSelectedMonth बनाने के लिए, एक महीने लेने के लिए की जरूरत है DisplayModeChanged परिभाषित


private void DatePickerCo_DisplayModeChanged(object sender, CalendarModeChangedEventArgs e) 
     { 
      var popup = this.Template.FindName(
       "PART_Popup", this) as Popup; 
      if (popup != null && popup.Child is System.Windows.Controls.Calendar) 
      { 
       var _calendar = popup.Child as System.Windows.Controls.Calendar; 
       if (_calendar.DisplayMode == CalendarMode.Month) 
       { 
        _calendar.DisplayMode = CalendarMode.Year; 

        if (IsDropDownOpen) 
        { 
         this.SelectedDate = GetSelectedMonth(_calendar.DisplayDate); 
         this.IsDropDownOpen = false; 
         ((System.Windows.Controls.Calendar)popup.Child).DisplayModeChanged -= new EventHandler(DatePickerCo_DisplayModeChanged); 
        } 
       } 

      } 
     } 

private DateTime? GetSelectedMonth(DateTime? selectedDate) 
     { 
      if (selectedDate == null) 
      { 
       selectedDate = DateTime.Now; 
      } 

      int monthDifferenceStart = DateTimeHelper.CompareYearMonth(selectedDate.Value, DisplayDateRangeStart); 
      int monthDifferenceEnd = DateTimeHelper.CompareYearMonth(selectedDate.Value, DisplayDateRangeEnd); 

      if (monthDifferenceStart >= 0 && monthDifferenceEnd 0, "monthDifferenceEnd should be greater than 0!"); 
        _selectedMonth = DateTimeHelper.DiscardDayTime(DisplayDateRangeEnd); 
       } 
      } 

      return _selectedMonth; 
     } 

यहाँ वहाँ कुछ चीज़ें है। दूसरी बात यह है कि विधि DateFimeHelper.cs नामक WPFToolkit की एक कक्षा का उपयोग करती है। ठीक है अब तक हमने महीने को लेने के लिए कार्यक्षमता बनाई है। लेकिन एक बार जब आप महीने कैलेंडर पर क्लिक करते हैं, तो हम महीने/वर्ष प्रारूप में चयनित तिथि दिखाने के लिए आगे बढ़ते हैं। के लिए पूरा है कि हम सिर्फ इस तरह हमारे कस्टम नियंत्रण के लिए एक विशिष्ट शैली बनाने के लिए की जरूरत है:

मेरा पहला जवाब में How to change format (e.g. dd/MMM/yyyy) of DateTimePicker in WPF application

मैं के बारे में सभी के बारे में बताया तारीख पिकर के कस्टम प्रारूप के साथ। उम्मीद है इससे आपको मदद होगी। कृपया कोई टिप्पणी या सुझाव दें, आप बस मुझे बताएं, सम्मान !!

+0

क्या आप Silverlight टूलकिट संस्करण के साथ किसी भी समान दृष्टिकोण से अवगत हैं? –

19

इस के आधार पर @Fernando Garcia के लिए धन्यवाद।

मैंने दिनांक/वर्ष चयन सक्षम करने के लिए डेटफिकर के लिए डेटफॉर्मेट और IsMonthYear संलग्न गुण लिखे हैं।

IsMonthYear संलग्न संपत्ति DatePicker के कैलेंडर को प्रतिबंधित करती है। कैलेंडर मोड से चयन को रोकने के लिए डिस्प्लेमोड को वर्ष और दशक तक .Month। यह डेटपिकर का दिन भाग भी सेट करता है। चयनित दिनांक 1.

डेटफॉर्मेट संलग्न संपत्ति इस परिदृश्य तक ही सीमित नहीं है, इसे डेटमिकर के प्रदर्शन और इनपुट के लिए प्रारूप स्ट्रिंग प्रदान करने के लिए IsMonthYear से अलग भी उपयोग किया जा सकता है।संलग्न संपत्तियों की

उदाहरण उपयोग:

<DatePicker my:DatePickerCalendar.IsMonthYear="True" 
      my:DatePickerDateFormat.DateFormat="MM/yyyy"/> 

IsMonthYear जुड़ी संपत्ति है:

public class DatePickerCalendar 
{ 
    public static readonly DependencyProperty IsMonthYearProperty = 
     DependencyProperty.RegisterAttached("IsMonthYear", typeof(bool), typeof(DatePickerCalendar), 
              new PropertyMetadata(OnIsMonthYearChanged)); 

    public static bool GetIsMonthYear(DependencyObject dobj) 
    { 
     return (bool)dobj.GetValue(IsMonthYearProperty); 
    } 

    public static void SetIsMonthYear(DependencyObject dobj, bool value) 
    { 
     dobj.SetValue(IsMonthYearProperty, value); 
    } 

    private static void OnIsMonthYearChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e) 
    { 
     var datePicker = (DatePicker) dobj; 

     Application.Current.Dispatcher 
      .BeginInvoke(DispatcherPriority.Loaded, 
         new Action<DatePicker, DependencyPropertyChangedEventArgs>(SetCalendarEventHandlers), 
         datePicker, e); 
    } 

    private static void SetCalendarEventHandlers(DatePicker datePicker, DependencyPropertyChangedEventArgs e) 
    { 
     if (e.NewValue == e.OldValue) 
      return; 

     if ((bool)e.NewValue) 
     { 
      datePicker.CalendarOpened += DatePickerOnCalendarOpened; 
      datePicker.CalendarClosed += DatePickerOnCalendarClosed; 
     } 
     else 
     { 
      datePicker.CalendarOpened -= DatePickerOnCalendarOpened; 
      datePicker.CalendarClosed -= DatePickerOnCalendarClosed; 
     } 
    } 

    private static void DatePickerOnCalendarOpened(object sender, RoutedEventArgs routedEventArgs) 
    { 
     var calendar = GetDatePickerCalendar(sender); 
     calendar.DisplayMode = CalendarMode.Year; 

     calendar.DisplayModeChanged += CalendarOnDisplayModeChanged; 
    } 

    private static void DatePickerOnCalendarClosed(object sender, RoutedEventArgs routedEventArgs) 
    { 
     var datePicker = (DatePicker) sender; 
     var calendar = GetDatePickerCalendar(sender); 
     datePicker.SelectedDate = calendar.SelectedDate; 

     calendar.DisplayModeChanged -= CalendarOnDisplayModeChanged; 
    } 

    private static void CalendarOnDisplayModeChanged(object sender, CalendarModeChangedEventArgs e) 
    { 
     var calendar = (Calendar) sender; 
     if (calendar.DisplayMode != CalendarMode.Month) 
      return; 

     calendar.SelectedDate = GetSelectedCalendarDate(calendar.DisplayDate); 

     var datePicker = GetCalendarsDatePicker(calendar); 
     datePicker.IsDropDownOpen = false; 
    } 

    private static Calendar GetDatePickerCalendar(object sender) 
    { 
     var datePicker = (DatePicker) sender; 
     var popup = (Popup) datePicker.Template.FindName("PART_Popup", datePicker); 
     return ((Calendar) popup.Child); 
    } 

    private static DatePicker GetCalendarsDatePicker(FrameworkElement child) 
    { 
     var parent = (FrameworkElement) child.Parent; 
     if (parent.Name == "PART_Root") 
      return (DatePicker) parent.TemplatedParent; 
     return GetCalendarsDatePicker(parent); 
    } 

    private static DateTime? GetSelectedCalendarDate(DateTime? selectedDate) 
    { 
     if (!selectedDate.HasValue) 
      return null; 
     return new DateTime(selectedDate.Value.Year, selectedDate.Value.Month, 1); 
    } 
} 

और DateFormat जुड़ी संपत्ति है:

public class DatePickerDateFormat 
{ 
    public static readonly DependencyProperty DateFormatProperty = 
     DependencyProperty.RegisterAttached("DateFormat", typeof (string), typeof (DatePickerDateFormat), 
              new PropertyMetadata(OnDateFormatChanged)); 

    public static string GetDateFormat(DependencyObject dobj) 
    { 
     return (string) dobj.GetValue(DateFormatProperty); 
    } 

    public static void SetDateFormat(DependencyObject dobj, string value) 
    { 
     dobj.SetValue(DateFormatProperty, value); 
    } 

    private static void OnDateFormatChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e) 
    { 
     var datePicker = (DatePicker) dobj; 

     Application.Current.Dispatcher.BeginInvoke(
      DispatcherPriority.Loaded, new Action<DatePicker>(ApplyDateFormat), datePicker); 
    } 

    private static void ApplyDateFormat(DatePicker datePicker) 
    { 
     var binding = new Binding("SelectedDate") 
      { 
       RelativeSource = new RelativeSource {AncestorType = typeof (DatePicker)}, 
       Converter = new DatePickerDateTimeConverter(), 
       ConverterParameter = new Tuple<DatePicker, string>(datePicker, GetDateFormat(datePicker)) 
      }; 
     var textBox = GetTemplateTextBox(datePicker); 
     textBox.SetBinding(TextBox.TextProperty, binding); 

     textBox.PreviewKeyDown -= TextBoxOnPreviewKeyDown; 
     textBox.PreviewKeyDown += TextBoxOnPreviewKeyDown; 

     datePicker.CalendarOpened -= DatePickerOnCalendarOpened; 
     datePicker.CalendarOpened += DatePickerOnCalendarOpened; 
    } 

    private static TextBox GetTemplateTextBox(Control control) 
    { 
     control.ApplyTemplate(); 
     return (TextBox) control.Template.FindName("PART_TextBox", control); 
    } 

    private static void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.Key != Key.Return) 
      return; 

     /* DatePicker subscribes to its TextBox's KeyDown event to set its SelectedDate if Key.Return was 
     * pressed. When this happens its text will be the result of its internal date parsing until it 
     * loses focus or another date is selected. A workaround is to stop the KeyDown event bubbling up 
     * and handling setting the DatePicker.SelectedDate. */ 

     e.Handled = true; 

     var textBox = (TextBox) sender; 
     var datePicker = (DatePicker) textBox.TemplatedParent; 
     var dateStr = textBox.Text; 
     var formatStr = GetDateFormat(datePicker); 
     datePicker.SelectedDate = DatePickerDateTimeConverter.StringToDateTime(datePicker, formatStr, dateStr); 
    } 

    private static void DatePickerOnCalendarOpened(object sender, RoutedEventArgs e) 
    { 
     /* When DatePicker's TextBox is not focused and its Calendar is opened by clicking its calendar button 
     * its text will be the result of its internal date parsing until its TextBox is focused and another 
     * date is selected. A workaround is to set this string when it is opened. */ 

     var datePicker = (DatePicker) sender; 
     var textBox = GetTemplateTextBox(datePicker); 
     var formatStr = GetDateFormat(datePicker); 
     textBox.Text = DatePickerDateTimeConverter.DateTimeToString(formatStr, datePicker.SelectedDate); 
    } 

    private class DatePickerDateTimeConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      var formatStr = ((Tuple<DatePicker, string>) parameter).Item2; 
      var selectedDate = (DateTime?) value; 
      return DateTimeToString(formatStr, selectedDate); 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      var tupleParam = ((Tuple<DatePicker, string>) parameter); 
      var dateStr = (string) value; 
      return StringToDateTime(tupleParam.Item1, tupleParam.Item2, dateStr); 
     } 

     public static string DateTimeToString(string formatStr, DateTime? selectedDate) 
     { 
      return selectedDate.HasValue ? selectedDate.Value.ToString(formatStr) : null; 
     } 

     public static DateTime? StringToDateTime(DatePicker datePicker, string formatStr, string dateStr) 
     { 
      DateTime date; 
      var canParse = DateTime.TryParseExact(dateStr, formatStr, CultureInfo.CurrentCulture, 
                DateTimeStyles.None, out date); 

      if (!canParse) 
       canParse = DateTime.TryParse(dateStr, CultureInfo.CurrentCulture, DateTimeStyles.None, out date); 

      return canParse ? date : datePicker.SelectedDate; 
     } 
    } 
} 
+0

thx, IsMonthYear संलग्न संपत्ति ने मुझे बहुत मदद की। मैंने इसे वीबी में अनुवादित किया, मेरी पोस्ट देखें। – GameAlchemist

+0

ग्रेट उत्तर, लेकिन एक छोटी सी बग है। जब आप ड्रॉपडाउन खोलते हैं और एक चयनित तिथि होती है, तो डेट-बॉक्स में टेक्स्ट क्षणिक रूप से मूल स्वरूपित स्ट्रिंग (उदा। डीडी/एमएम/yyyy), और नई स्वरूपित स्ट्रिंग (उदा। एमएम/yyyy) पर झिलमिलाहट करता है। इसे ठीक करने के लिए मुझे DatePickerdateFormat क्लास में कुछ हैकर करना था। –

3

मैं अनुवाद साइमन वीबी में जवाब, मैं यहाँ फिर से पोस्ट करें sults (कृपया उसे क्रेडिट दें)

Imports System.Windows.Threading 
Imports System.Windows.Controls.Primitives 
Imports System.Windows.Controls 

''' <summary>  Allows the Date Picker Calendar to select month. 
'''      Use with the attached property IsMonthYear Property. 
''' </summary> 
''' <remarks> Source : https://stackoverflow.com/questions/1798513/wpf-toolkit-datepicker-month-year-only 
'''   Author : </remarks> 
Public Class DatePickerCalendar 

Public Shared IsMonthYearProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsMonthYear", GetType(System.Boolean), GetType(DatePickerCalendar), New PropertyMetadata(AddressOf OnIsMonthYearChanged)) 

Public Shared Function GetIsMonthYear(ByVal dobj As DependencyObject) As Boolean 
    Return CType(dobj.GetValue(IsMonthYearProperty), Boolean) 
End Function 

Public Shared Sub SetIsMonthYear(ByVal dobj As DependencyObject, ByVal value As Boolean) 
    dobj.SetValue(IsMonthYearProperty, value) 
End Sub 

Private Shared Sub OnIsMonthYearChanged(ByVal dobj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs) 
    Dim MyDatePicker = CType(dobj, DatePicker) 
    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, _ 
        New Action(Of DatePicker, DependencyPropertyChangedEventArgs)(AddressOf SetCalendarEventHandlers), MyDatePicker, e) 
End Sub 

Private Shared Sub SetCalendarEventHandlers(ByVal datePicker As DatePicker, ByVal e As DependencyPropertyChangedEventArgs) 
    If (e.NewValue = e.OldValue) Then 
     Return 
    End If 
    If CType(e.NewValue, Boolean) Then 
     AddHandler datePicker.CalendarOpened, AddressOf DatePickerOnCalendarOpened 
     AddHandler datePicker.CalendarClosed, AddressOf DatePickerOnCalendarClosed 
    Else 
     RemoveHandler datePicker.CalendarOpened, AddressOf DatePickerOnCalendarOpened 
     RemoveHandler datePicker.CalendarClosed, AddressOf DatePickerOnCalendarClosed 
    End If 
End Sub 

Private Shared Sub DatePickerOnCalendarOpened(ByVal sender As Object, ByVal routedEventArgs As RoutedEventArgs) 
    Dim MyCalendar = GetDatePickerCalendar(sender) 
    MyCalendar.DisplayMode = CalendarMode.Year 
    AddHandler MyCalendar.DisplayModeChanged, AddressOf CalendarOnDisplayModeChanged 
End Sub 

Private Shared Sub DatePickerOnCalendarClosed(ByVal sender As Object, ByVal routedEventArgs As RoutedEventArgs) 
    Dim MyDatePicker = CType(sender, DatePicker) 
    Dim MyCalendar = GetDatePickerCalendar(sender) 
    MyDatePicker.SelectedDate = MyCalendar.SelectedDate 
    RemoveHandler MyCalendar.DisplayModeChanged, AddressOf CalendarOnDisplayModeChanged 
End Sub 

Private Shared Sub CalendarOnDisplayModeChanged(ByVal sender As Object, ByVal e As CalendarModeChangedEventArgs) 
    Dim MyCalendar = CType(sender, Calendar) 
    If (MyCalendar.DisplayMode <> CalendarMode.Month) Then 
     Return 
    End If 
    MyCalendar.SelectedDate = GetSelectedCalendarDate(MyCalendar.DisplayDate) 
    Dim MyDatePicker = GetCalendarsDatePicker(MyCalendar) 
    MyDatePicker.IsDropDownOpen = False 
End Sub 

Private Shared Function GetDatePickerCalendar(ByVal sender As Object) As Calendar 
    Dim MyDatePicker = CType(sender, DatePicker) 
    Dim MyPopup = CType(MyDatePicker.Template.FindName("PART_Popup", MyDatePicker), Popup) 
    Return CType(MyPopup.Child, Calendar) 
End Function 

Private Shared Function GetCalendarsDatePicker(ByVal child As FrameworkElement) As DatePicker 
    Dim MyParent = CType(child.Parent, FrameworkElement) 
    If (MyParent.Name = "PART_Root") Then 
     Return CType(MyParent.TemplatedParent, DatePicker) 
    End If 
    Return GetCalendarsDatePicker(MyParent) 
End Function 

Private Shared Function GetSelectedCalendarDate(ByVal selectedDate As DateTime?) As DateTime? 
    If Not selectedDate.HasValue Then 
     Return Nothing 
    End If 
    Return New DateTime(selectedDate.Value.Year, selectedDate.Value.Month, 1) 
End Function 
End Class 

लेकिन प्रारूप वर्ग के लिए, मैं इसे काम नहीं कर सका।
मैंने महीने और वर्ष के प्रदर्शन के लिए पेट्रीकोल से (सरल) उत्तर (सरल) उत्तर में उपयोग किया और स्लीघ्ली संशोधित किया। स्रोत:
Changing the string format of the WPF DatePicker

<DatePicker SelectedDate="{Binding FromDate}" 
        l:DatePickerCalendar.IsMonthYear="True" 
        x:Name="MonthCalendar" HorizontalAlignment="Center"     
       > 
     <DatePicker.Resources> 
      <!--Source : https://stackoverflow.com/questions/3819832/changing-the-string-format-of-the-wpf-datepicker 
       Author : petrycol --> 
      <Style TargetType="{x:Type DatePickerTextBox}"> 
       <Setter Property="Control.Template"> 
        <Setter.Value> 
         <ControlTemplate> 
          <TextBox Width="60" TextAlignment="Center" x:Name="PART_TextBox" 
            Text="{Binding Path=SelectedDate, StringFormat='MM yy', 
            RelativeSource={RelativeSource AncestorType={x:Type DatePicker}},FallbackValue='-- --'}" /> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Style> 
     </DatePicker.Resources> 
     <!--CalendarOpened="DatePicker_CalendarOpened"--> 
    </DatePicker> 
4

Simon's brilliant answer को जोड़ने के लिए, मैं एक बग जहां पाठ बॉक्स क्षण भर dd/एम एम/yyyy (मूल स्ट्रिंग प्रारूप) और एम एम के बीच flickers को रोकने के लिए DatePickerDateFormat.cs लिए कुछ परिवर्तन किए हैं/yyyy (ओवरराइड स्ट्रिंग प्रारूप)।

ऐसा होता है कि डेटपिकर ड्रॉपडाउन खोले जाने से पहले आंतरिक रूप से PART_Textbox टेक्स्ट को आंतरिक रूप से सेट करता है। यह इसे स्ट्रिंग स्वरूपित पाठ पर सेट करता है और इसके बारे में आप यह कर सकते हैं - यह आपके बाध्यकारी को ओवरराइड करेगा।

इस व्यवहार को रोकने के लिए, मैंने यह कोड DatePickerDateFormat class from above पर जोड़ा।

  1. ApplyDateFormat में

    , ड्रॉप-डाउन बटन मिलता है और संभाल PreviewMouseUp

    private static void ApplyDateFormat(DatePicker datePicker) 
    { 
        var binding = new Binding("SelectedDate") 
            { 
             RelativeSource = new RelativeSource { AncestorType = typeof(DatePicker) }, 
             Converter = new DatePickerDateTimeConverter(), 
             ConverterParameter = new Tuple<DatePicker, string>(datePicker, GetDateFormat(datePicker)), 
             StringFormat = GetDateFormat(datePicker) // This is also new but didnt seem to help 
            }; 
    
        var textBox = GetTemplateTextBox(datePicker); 
        textBox.SetBinding(TextBox.TextProperty, binding); 
    
        textBox.PreviewKeyDown -= TextBoxOnPreviewKeyDown; 
        textBox.PreviewKeyDown += TextBoxOnPreviewKeyDown; 
    
        var dropDownButton = GetTemplateButton(datePicker); 
    
        datePicker.CalendarOpened -= DatePickerOnCalendarOpened; 
        datePicker.CalendarOpened += DatePickerOnCalendarOpened; 
    
        // Handle Dropdownbutton PreviewMouseUp to prevent issue of flickering textboxes 
        dropDownButton.PreviewMouseUp -= DropDownButtonPreviewMouseUp; 
        dropDownButton.PreviewMouseUp += DropDownButtonPreviewMouseUp; 
    } 
    
    private static ButtonBase GetTemplateButton(DatePicker datePicker) 
    { 
        return (ButtonBase)datePicker.Template.FindName("PART_Button", datePicker); 
    } 
    

जब PreviewMouseUp आग, अगर वहाँ एक चयनित दिनांक होता है, वहां ड्रापडाउन दिखाया व्यवहार को ओवरराइड (हम सब कुछ है कि नकल डेटपिकर करता है, लेकिन हम PART_TextBox टेक्स्ट सेट नहीं करते हैं)

/// <summary> 
    ///  Prevents a bug in the DatePicker, where clicking the Dropdown open button results in Text being set to default formatting regardless of StringFormat or binding overrides 
    /// </summary> 
    private static void DropDownButtonPreviewMouseUp(object sender, MouseButtonEventArgs e) 
    { 
     var fe = sender as FrameworkElement; 
     if (fe == null) return; 

     var datePicker = fe.TryFindAncestorOrSelf<DatePicker>(); 
     if (datePicker == null || datePicker.SelectedDate == null) return;    

     var dropDownButton = GetTemplateButton(datePicker); 

     // Dropdown button was clicked 
     if (e.OriginalSource == dropDownButton && datePicker.IsDropDownOpen == false) 
     {         
      // Open dropdown 
      datePicker.SetCurrentValue(DatePicker.IsDropDownOpenProperty, true); 

      // Mimic everything else in the standard DatePicker dropdown opening *except* setting textbox value 
      datePicker.SetCurrentValue(DatePicker.DisplayDateProperty, datePicker.SelectedDate.Value); 

      // Important otherwise calendar does not work 
      dropDownButton.ReleaseMouseCapture(); 

      // Prevent datePicker.cs from handling this event 
      e.Handled = true;     
     } 
    } 

जहां विस्तार आयन विधि TryFindAncestorOrल्फ प्रकार के ऑब्जेक्ट को खोजने के लिए दृश्य पेड़ को चलाता है। आप इसे यहां कार्यान्वित कर सकते हैं: http://www.hardcodet.net/2008/02/find-wpf-parent

आशा है कि इससे किसी की मदद मिलेगी!

+0

के नीचे समाधान विधि का मूल नाम 'TryFindParent' है :) – WiiMaxx

+0

डॉ एबीटी, मूल प्रारूप में झिलमिलाहट से संबंधित फिक्स के लिए धन्यवाद। मैंने आपका परिवर्तन जोड़ा है, हालांकि, यदि कैलेंडर खुला है और आप नियंत्रण से दूर क्लिक करते हैं, तो कैलेंडर खुला रहता है। जब आप नियंत्रण से दूर क्लिक करते हैं तो सामान्य डेटपिकर व्यवहार कैलेंडर नियंत्रण को बंद करना है। ऐसा कोई विचार क्यों है कि यह क्यों हो रहा है? – user1202134

+0

भगवान मुझे डर नहीं है, मैंने 3 साल पहले इस परियोजना पर काम किया था! –

7

यह सभी अतिरिक्त आवश्यक कोड और Windows और Microsoft नियंत्रण तय के बीच संदर्भ संघर्षों के साथ सहित Simon's और Dr. ABT's जवाब, का एक संयोजन है।

यह बहुत हास्यास्पद है कि इसे प्राप्त करने के लिए 345 लाइनों की एक कक्षा की आवश्यकता होती है, लेकिन यदि आप DatePickerCalendar.cs (अपने नामस्थान के साथ), अपनी परियोजना का निर्माण करें, और निम्न XAML का उपयोग करें, तो यह काम करना चाहिए।

<DatePicker local:DatePickerCalendar.IsMonthYear="True" 
      local:DatePickerDateFormat.DateFormat="MMM-yyyy" 
      Text="MMM-yyyy"></DatePicker> 

DatePickerCalendar.cs

using System; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows.Data; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Threading; 
using Calendar = System.Windows.Controls.Calendar; 
using CalendarMode = System.Windows.Controls.CalendarMode; 
using CalendarModeChangedEventArgs = System.Windows.Controls.CalendarModeChangedEventArgs; 
using DatePicker = System.Windows.Controls.DatePicker; 

namespace <YourProject> 
{ 
    public class DatePickerCalendar 
    { 
     public static readonly DependencyProperty IsMonthYearProperty = 
      DependencyProperty.RegisterAttached("IsMonthYear", typeof(bool), typeof(DatePickerCalendar), 
               new PropertyMetadata(OnIsMonthYearChanged)); 

     public static bool GetIsMonthYear(DependencyObject dobj) 
     { 
      return (bool)dobj.GetValue(IsMonthYearProperty); 
     } 

     public static void SetIsMonthYear(DependencyObject dobj, bool value) 
     { 
      dobj.SetValue(IsMonthYearProperty, value); 
     } 

     private static void OnIsMonthYearChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e) 
     { 
      var datePicker = (DatePicker)dobj; 

      Application.Current.Dispatcher 
       .BeginInvoke(DispatcherPriority.Loaded, 
          new Action<DatePicker, DependencyPropertyChangedEventArgs>(SetCalendarEventHandlers), 
          datePicker, e); 
     } 

     private static void SetCalendarEventHandlers(DatePicker datePicker, DependencyPropertyChangedEventArgs e) 
     { 
      if (e.NewValue == e.OldValue) 
       return; 

      if ((bool)e.NewValue) 
      { 
       datePicker.CalendarOpened += DatePickerOnCalendarOpened; 
       datePicker.CalendarClosed += DatePickerOnCalendarClosed; 
      } 
      else 
      { 
       datePicker.CalendarOpened -= DatePickerOnCalendarOpened; 
       datePicker.CalendarClosed -= DatePickerOnCalendarClosed; 
      } 
     } 

     private static void DatePickerOnCalendarOpened(object sender, RoutedEventArgs routedEventArgs) 
     { 
      var calendar = GetDatePickerCalendar(sender); 
      calendar.DisplayMode = CalendarMode.Year; 

      calendar.DisplayModeChanged += CalendarOnDisplayModeChanged; 
     } 

     private static void DatePickerOnCalendarClosed(object sender, RoutedEventArgs routedEventArgs) 
     { 
      var datePicker = (DatePicker)sender; 
      var calendar = GetDatePickerCalendar(sender); 
      datePicker.SelectedDate = calendar.SelectedDate; 

      calendar.DisplayModeChanged -= CalendarOnDisplayModeChanged; 
     } 

     private static void CalendarOnDisplayModeChanged(object sender, CalendarModeChangedEventArgs e) 
     { 
      var calendar = (Calendar)sender; 
      if (calendar.DisplayMode != CalendarMode.Month) 
       return; 

      calendar.SelectedDate = GetSelectedCalendarDate(calendar.DisplayDate); 

      var datePicker = GetCalendarsDatePicker(calendar); 
      datePicker.IsDropDownOpen = false; 
     } 

     private static Calendar GetDatePickerCalendar(object sender) 
     { 
      var datePicker = (DatePicker)sender; 
      var popup = (Popup)datePicker.Template.FindName("PART_Popup", datePicker); 
      return ((Calendar)popup.Child); 
     } 

     private static DatePicker GetCalendarsDatePicker(FrameworkElement child) 
     { 
      var parent = (FrameworkElement)child.Parent; 
      if (parent.Name == "PART_Root") 
       return (DatePicker)parent.TemplatedParent; 
      return GetCalendarsDatePicker(parent); 
     } 

     private static DateTime? GetSelectedCalendarDate(DateTime? selectedDate) 
     { 
      if (!selectedDate.HasValue) 
       return null; 
      return new DateTime(selectedDate.Value.Year, selectedDate.Value.Month, 1); 
     } 
    } 

    public class DatePickerDateFormat 
    { 
     public static readonly DependencyProperty DateFormatProperty = 
      DependencyProperty.RegisterAttached("DateFormat", typeof(string), typeof(DatePickerDateFormat), 
               new PropertyMetadata(OnDateFormatChanged)); 

     public static string GetDateFormat(DependencyObject dobj) 
     { 
      return (string)dobj.GetValue(DateFormatProperty); 
     } 

     public static void SetDateFormat(DependencyObject dobj, string value) 
     { 
      dobj.SetValue(DateFormatProperty, value); 
     } 

     private static void OnDateFormatChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e) 
     { 
      var datePicker = (DatePicker)dobj; 

      Application.Current.Dispatcher.BeginInvoke(
       DispatcherPriority.Loaded, new Action<DatePicker>(ApplyDateFormat), datePicker); 
     } 
     private static void ApplyDateFormat(DatePicker datePicker) 
     { 
      var binding = new Binding("SelectedDate") 
      { 
       RelativeSource = new RelativeSource { AncestorType = typeof(DatePicker) }, 
       Converter = new DatePickerDateTimeConverter(), 
       ConverterParameter = new Tuple<DatePicker, string>(datePicker, GetDateFormat(datePicker)), 
       StringFormat = GetDateFormat(datePicker) // This is also new but didnt seem to help 
      }; 

      var textBox = GetTemplateTextBox(datePicker); 
      textBox.SetBinding(TextBox.TextProperty, binding); 

      textBox.PreviewKeyDown -= TextBoxOnPreviewKeyDown; 
      textBox.PreviewKeyDown += TextBoxOnPreviewKeyDown; 

      var dropDownButton = GetTemplateButton(datePicker); 

      datePicker.CalendarOpened -= DatePickerOnCalendarOpened; 
      datePicker.CalendarOpened += DatePickerOnCalendarOpened; 

      // Handle Dropdownbutton PreviewMouseUp to prevent issue of flickering textboxes 
      dropDownButton.PreviewMouseUp -= DropDownButtonPreviewMouseUp; 
      dropDownButton.PreviewMouseUp += DropDownButtonPreviewMouseUp; 
     } 

     private static ButtonBase GetTemplateButton(DatePicker datePicker) 
     { 
      return (ButtonBase)datePicker.Template.FindName("PART_Button", datePicker); 
     } 


     /// <summary> 
     ///  Prevents a bug in the DatePicker, where clicking the Dropdown open button results in Text being set to default formatting regardless of StringFormat or binding overrides 
     /// </summary> 
     private static void DropDownButtonPreviewMouseUp(object sender, MouseButtonEventArgs e) 
     { 
      var fe = sender as FrameworkElement; 
      if (fe == null) return; 

      var datePicker = fe.TryFindParent<DatePicker>(); 
      if (datePicker == null || datePicker.SelectedDate == null) return; 

      var dropDownButton = GetTemplateButton(datePicker); 

      // Dropdown button was clicked 
      if (e.OriginalSource == dropDownButton && datePicker.IsDropDownOpen == false) 
      { 
       // Open dropdown 
       datePicker.SetCurrentValue(DatePicker.IsDropDownOpenProperty, true); 

       // Mimic everything else in the standard DatePicker dropdown opening *except* setting textbox value 
       datePicker.SetCurrentValue(DatePicker.DisplayDateProperty, datePicker.SelectedDate.Value); 

       // Important otherwise calendar does not work 
       dropDownButton.ReleaseMouseCapture(); 

       // Prevent datePicker.cs from handling this event 
       e.Handled = true; 
      } 
     } 



     private static TextBox GetTemplateTextBox(Control control) 
     { 
      control.ApplyTemplate(); 
      return (TextBox)control?.Template?.FindName("PART_TextBox", control); 
     } 

     private static void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs e) 
     { 
      if (e.Key != Key.Return) 
       return; 

      /* DatePicker subscribes to its TextBox's KeyDown event to set its SelectedDate if Key.Return was 
      * pressed. When this happens its text will be the result of its internal date parsing until it 
      * loses focus or another date is selected. A workaround is to stop the KeyDown event bubbling up 
      * and handling setting the DatePicker.SelectedDate. */ 

      e.Handled = true; 

      var textBox = (TextBox)sender; 
      var datePicker = (DatePicker)textBox.TemplatedParent; 
      var dateStr = textBox.Text; 
      var formatStr = GetDateFormat(datePicker); 
      datePicker.SelectedDate = DatePickerDateTimeConverter.StringToDateTime(datePicker, formatStr, dateStr); 
     } 

     private static void DatePickerOnCalendarOpened(object sender, RoutedEventArgs e) 
     { 
      /* When DatePicker's TextBox is not focused and its Calendar is opened by clicking its calendar button 
      * its text will be the result of its internal date parsing until its TextBox is focused and another 
      * date is selected. A workaround is to set this string when it is opened. */ 

      var datePicker = (DatePicker)sender; 
      var textBox = GetTemplateTextBox(datePicker); 
      var formatStr = GetDateFormat(datePicker); 
      textBox.Text = DatePickerDateTimeConverter.DateTimeToString(formatStr, datePicker.SelectedDate); 
     } 

     private class DatePickerDateTimeConverter : IValueConverter 
     { 
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
      { 
       var formatStr = ((Tuple<DatePicker, string>)parameter).Item2; 
       var selectedDate = (DateTime?)value; 
       return DateTimeToString(formatStr, selectedDate); 
      } 

      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
      { 
       var tupleParam = ((Tuple<DatePicker, string>)parameter); 
       var dateStr = (string)value; 
       return StringToDateTime(tupleParam.Item1, tupleParam.Item2, dateStr); 
      } 

      public static string DateTimeToString(string formatStr, DateTime? selectedDate) 
      { 
       return selectedDate.HasValue ? selectedDate.Value.ToString(formatStr) : null; 
      } 

      public static DateTime? StringToDateTime(DatePicker datePicker, string formatStr, string dateStr) 
      { 
       DateTime date; 
       var canParse = DateTime.TryParseExact(dateStr, formatStr, CultureInfo.CurrentCulture, 
                 DateTimeStyles.None, out date); 

       if (!canParse) 
        canParse = DateTime.TryParse(dateStr, CultureInfo.CurrentCulture, DateTimeStyles.None, out date); 

       return canParse ? date : datePicker.SelectedDate; 
      } 


     } 

    } 



    public static class FEExten 
    { 
     /// <summary> 
     /// Finds a parent of a given item on the visual tree. 
     /// </summary> 
     /// <typeparam name="T">The type of the queried item.</typeparam> 
     /// <param name="child">A direct or indirect child of the 
     /// queried item.</param> 
     /// <returns>The first parent item that matches the submitted 
     /// type parameter. If not matching item can be found, a null 
     /// reference is being returned.</returns> 
     public static T TryFindParent<T>(this DependencyObject child) 
      where T : DependencyObject 
     { 
      //get parent item 
      DependencyObject parentObject = GetParentObject(child); 

      //we've reached the end of the tree 
      if (parentObject == null) return null; 

      //check if the parent matches the type we're looking for 
      T parent = parentObject as T; 
      if (parent != null) 
      { 
       return parent; 
      } 
      else 
      { 
       //use recursion to proceed with next level 
       return TryFindParent<T>(parentObject); 
      } 
     } 

     /// <summary> 
     /// This method is an alternative to WPF's 
     /// <see cref="VisualTreeHelper.GetParent"/> method, which also 
     /// supports content elements. Keep in mind that for content element, 
     /// this method falls back to the logical tree of the element! 
     /// </summary> 
     /// <param name="child">The item to be processed.</param> 
     /// <returns>The submitted item's parent, if available. Otherwise 
     /// null.</returns> 
     public static DependencyObject GetParentObject(this DependencyObject child) 
     { 
      if (child == null) return null; 

      //handle content elements separately 
      ContentElement contentElement = child as ContentElement; 
      if (contentElement != null) 
      { 
       DependencyObject parent = ContentOperations.GetParent(contentElement); 
       if (parent != null) return parent; 

       FrameworkContentElement fce = contentElement as FrameworkContentElement; 
       return fce != null ? fce.Parent : null; 
      } 

      //also try searching for parent in framework elements (such as DockPanel, etc) 
      FrameworkElement frameworkElement = child as FrameworkElement; 
      if (frameworkElement != null) 
      { 
       DependencyObject parent = frameworkElement.Parent; 
       if (parent != null) return parent; 
      } 

      //if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper 
      return VisualTreeHelper.GetParent(child); 
     } 
    } 
} 

स्क्रीनशॉट

+0

ग्रेट दृष्टिकोण। मेरा सुझाव है कि इस लाइन में कक्षा को अपडेट करें: रिटर्न (टेक्स्टबॉक्स) नियंत्रण? टेम्पलेट? फ़िंडनाम ("PART_TextBox", नियंत्रण); प्रश्न चिह्न हटाएं। मैंने केवल मेरे कोड पर प्रतिलिपि बनाई और पेस्ट किया और ठीक काम करने लगता है। धन्यवाद –

संबंधित मुद्दे