Вопрос такой возможно ли создание/изменение стиля CalendarItem так чтобы можно было отображать еще и доп значение(грубо говоря номер) из модели для BlackoutDates?
Хочется получить что-то вот такого вида только где 16 и BlackoutDates берутся из модели. причем цифра над датой меняется в зависимости от диапазона "выбора" к сожалению я не смог так делать для скрина. Имеется ввиду что первый набор BlackoutDates(1-14) содержит номер 16 второй(15) 17, третий(23-28)18. вот такую логику хочется. Это возможно?
Насколько я понимаю Calendar.BlackoutDates можно привязать через Attached.property
Добавляю предложенные изменения в стиле CalendarDayButtonStyle. Я выкинул из стиля все действия которые мне ненужны(надеюсь).
<Style x:Key="CalendarDayButtonStyle1" TargetType="{x:Type CalendarDayButton}">
<Setter Property="MinWidth" Value="5"/>
<Setter Property="MinHeight" Value="5"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Height" Value="25"/>
<Setter Property="Width" Value="25"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarDayButton}">
<Grid >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="BlackoutDayStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="NormalDay"/>
<VisualState x:Name="BlackoutDay">
<Storyboard>
<!--<DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Blackout"/>-->
<DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="TodayBackground"/>
<DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="UpName"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="TodayBackground" Fill="#FFAAAAAA" Opacity="0" RadiusY="1" RadiusX="1"/>
<Border BorderThickness="1" BorderBrush="DarkGray"/>
<Rectangle x:Name="SelectedBackground" Fill="#FFBADDE9" Opacity="0" RadiusY="1" RadiusX="1"/>
<ContentPresenter x:Name="NormalText"
TextElement.Foreground="#FF333333"
Margin="5,1,2,1"
TextElement.FontSize="11"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
/>
<Label x:Name="UpName" Content="16" FontSize="9" Padding="0" Opacity="0" BorderThickness="1" BorderBrush="LightGray" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
планируется что биндин будет к элементу UpName
в общем допилил проект не кликабельнная отображалка диапазонов для месяца с доп информацией. Связь элементов календаря получилось сделать только через мультибиндинг и конверторы. в общем как-то так.
XAML
<UserControl x:Class="YearClendar.MonthCalendar.MonthCalendar"
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:YearClendar.MonthCalendar"
xmlns:Convert="clr-namespace:MonthCalendar.Converters"
xmlns:helpers="clr-namespace:MonthCalendar.Helpers"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" >
<UserControl.Resources>
<Convert:NumberDateConverter x:Key="NumberDateConverter"/>
<Convert:NeedShowBack x:Key="NeedShowBack"/>
<Convert:BackgroundItemConverter x:Key="BackgroundItemConverter"/>
<Convert:NumForeItemConverter x:Key="NumForeItemConverter"/>
<Style x:Key="CalendarStyle_2" TargetType="{x:Type Calendar}">
<Setter Property="Foreground" Value="#FF333333"/>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFE4EAF0" Offset="0" />
<GradientStop Color="#FFECF0F4" Offset="0.16"/>
<GradientStop Color="#FFFCFCFD" Offset="0.16"/>
<GradientStop Color="#FFFFFFFF" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Calendar}">
<StackPanel x:Name="PART_Root" HorizontalAlignment="Center">
<CalendarItem x:Name="PART_CalendarItem"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Style="{TemplateBinding CalendarItemStyle}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CalendarButtonStyle_2" TargetType="{x:Type CalendarButton}">
<Setter Property="Background" Value="#FFBADDE9"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="MinHeight" Value="42"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarButton}">
<Grid>
<ContentPresenter x:Name="NormalText" TextElement.Foreground="#FF000000" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1,0,1,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CalendarItemStyle_2" TargetType="{x:Type CalendarItem}">
<Setter Property="Margin" Value="0,1,0,1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarItem}">
<ControlTemplate.Resources>
<DataTemplate x:Key="{x:Static CalendarItem.DayTitleTemplateResourceKey}">
<TextBlock Foreground="#FF000000" FontWeight="Bold" FontSize="9.5"
FontFamily="Verdana" HorizontalAlignment="Center" Margin="0,2,0,2"
Text="{Binding}" VerticalAlignment="Center"/>
</DataTemplate>
</ControlTemplate.Resources>
<Grid x:Name="PART_Root">
<Grid.Resources>
<SolidColorBrush x:Key="DisabledColor" Color="#A5FFFFFF"/>
</Grid.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_DisabledVisual"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="1">
<Border BorderBrush="#FFFFFFFF" BorderThickness="2" CornerRadius="1">
<Grid>
<Grid.Resources>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock
Grid.Column="1"
FontWeight="Bold"
Focusable="False"
FontSize="10.5"
Foreground="Black"
HorizontalAlignment="Stretch"
TextAlignment="Center"
Grid.Row="0"
VerticalAlignment="Stretch"
Text="{Binding ElementName=PART_HeaderButton,Path=Content}" Margin="0" Width="Auto"
/>
<Button x:Name="PART_HeaderButton" Grid.Column="1" FontWeight="Bold" Visibility="Collapsed" FontSize="10.5" HorizontalAlignment="Center" Grid.Row="0" VerticalAlignment="Center"/>
<Grid x:Name="PART_MonthView" Grid.ColumnSpan="3" HorizontalAlignment="Center" Margin="1,-1,1,1" Grid.Row="1" Visibility="Visible">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
</Grid>
</Grid>
</Border>
</Border>
<Rectangle x:Name="PART_DisabledVisual" Fill="{StaticResource DisabledColor}" Opacity="0" RadiusY="2" RadiusX="2" Stretch="Fill" Stroke="{StaticResource DisabledColor}" StrokeThickness="1" Visibility="Collapsed"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" TargetName="PART_DisabledVisual" Value="Visible"/>
</Trigger>
<DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Year">
<Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Decade">
<Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="ButtonControlTemplate_2" TargetType="{x:Type Button}">
<ContentPresenter x:Name="buttonContent" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" TextElement.Foreground="#FF333333" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="0" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
</ContentPresenter>
</ControlTemplate>
<Style x:Key="CalendarDayButtonStyle_2" TargetType="{x:Type CalendarDayButton}">
<Setter Property="MinWidth" Value="5"/>
<Setter Property="MinHeight" Value="5"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Height" Value="25"/>
<Setter Property="Width" Value="25"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarDayButton}">
<Grid >
<Grid.Resources>
<helpers:BindingProxy x:Key="proxy" Data="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MonthCalendar}}, Path=DataContext}" />
</Grid.Resources>
<Border BorderThickness="1" BorderBrush="DarkGray"/>
<Rectangle x:Name="AccentBackground" RadiusX="1" RadiusY="1" Opacity="0.3" IsHitTestVisible="False">
<Rectangle.Fill>
<MultiBinding Converter="{StaticResource BackgroundItemConverter}">
<MultiBinding.Bindings>
<Binding />
<Binding Source="{StaticResource proxy}" Path="Data.SelectedDays"/>
</MultiBinding.Bindings>
</MultiBinding>
</Rectangle.Fill>
<Rectangle.Visibility>
<MultiBinding Converter="{StaticResource NeedShowBack}">
<MultiBinding.Bindings>
<Binding />
<Binding Source="{StaticResource proxy}" Path="Data.SelectedDays"/>
</MultiBinding.Bindings>
</MultiBinding>
</Rectangle.Visibility>
</Rectangle>
<Label x:Name="NormalText" TextElement.Foreground="#FF000000"
Padding="0"
Margin="5,1,2,1"
TextElement.FontSize="11"
Content="{Binding Day}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"/>
<Label x:Name="UpName" FontSize="9"
Padding="2,0,0,0"
BorderThickness="1"
VerticalAlignment="Top"
HorizontalAlignment="Left">
<Label.Foreground>
<MultiBinding Converter="{StaticResource NumForeItemConverter}">
<MultiBinding.Bindings>
<Binding />
<Binding Source="{StaticResource proxy}" Path="Data.SelectedDays"/>
</MultiBinding.Bindings>
</MultiBinding>
</Label.Foreground>
<MultiBinding Converter="{StaticResource NumberDateConverter}">
<MultiBinding.Bindings>
<Binding />
<Binding Source="{StaticResource proxy}" Path="Data.SelectedDays"/>
</MultiBinding.Bindings>
</MultiBinding>
<Label.Style>
<Style TargetType="{x:Type Label}">
<Setter Property="BorderBrush" Value="Gray"/>
<Style.Triggers>
<Trigger Property="Content" Value="{x:Null}">
<Setter Property="BorderBrush" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
класс модель
namespace MonthCalendar.Model
{
public class MonthModel : BaseModel
{
private DateTime p_DisplayDate;
private DateTime m_OldDisplayDate;
Dictionary<DateTime, SelectDayElemet> _SelectedDays;
public Dictionary<DateTime, SelectDayElemet> SelectedDays
{
get { return _SelectedDays; }
set {
_SelectedDays =value;
OnPropertyChanged(()=>SelectedDays);
}
}
public void Update()
{
OnPropertyChanged(() => SelectedDays);
OnPropertyChanged(() => DisplayDate);
OnPropertyChanged(() => DisplayDateStart);
OnPropertyChanged(() => DisplayDateEnd);
}
public MonthModel()
{
this.Initialize();
}
public event EventHandler RefreshRequested;
private void RequestRefresh()
{
RefreshRequested?.Invoke(this, new EventArgs());
}
public DateTime DisplayDate
{
get { return GetFirstDay(); }
set
{
WorkMonth = value;
GetFirstDay();
OnPropertyChanged(() => DisplayDate);
}
}
DateTime GetFirstDay()
{
DateTime tmp1 = new DateTime(WorkMonth.Year, WorkMonth.Month, 1);
return new DateTime(WorkMonth.Year, WorkMonth.Month, 1);
}
DateTime GetLastDay()
{
if (WorkMonth.Month==12)
return new DateTime(WorkMonth.Year, WorkMonth.Month, 31);
DateTime tmp2 = new DateTime(WorkMonth.Year, WorkMonth.Month + 1, 1);
DateTime tmp3 = tmp2.AddDays(-1);
return new DateTime(tmp3.Year, tmp3.Month, tmp3.Day);
}
private void Initialize()
{
WorkMonth = DateTime.Today;
SelectedDays = new Dictionary<DateTime, SelectDayElemet>();
this.PropertyChanged += OnPropertyChanged;
}
public DateTime DisplayDateStart
{
get { return GetFirstDay(); }
set { }
}
public DateTime DisplayDateEnd
{
get { return GetLastDay(); }
set { }
}
DateTime _p_DisplayDate;
public DateTime WorkMonth
{
get { return _p_DisplayDate; }
set
{
_p_DisplayDate = value;
OnPropertyChanged(() => p_DisplayDate);
OnPropertyChanged(() => DisplayDate);
OnPropertyChanged(() => DisplayDateStart);
OnPropertyChanged(() => DisplayDateEnd);
}
}
private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// Ignore properties other than DisplayDate
if (e.PropertyName != "DisplayDate") return;
// Ignore change if date is DateTime.MinValue
if (DisplayDate == DateTime.MinValue) return;
// Ignore change if month is the same
if (DisplayDate.IsSameMonthAs(m_OldDisplayDate)) return;
// Update OldDisplayDate
m_OldDisplayDate = p_DisplayDate;
}
#region Administrative Properties
public virtual bool IgnorePropertyChangeEvents { get; set; }
#endregion
}
}
класс элемента унаследован от BaseModel в которой реализованы интерфейсы
INotifyPropertyChanging, INotifyPropertyChanged
public class SelectDayElemet: BaseModel
{
public SelectDayElemet()
{
//Date = new DateTime();
Background = new LinearGradientBrush(
new GradientStopCollection()
{
new GradientStop((Color)ColorConverter.ConvertFromString("#FFE4EAF0"),0),
new GradientStop((Color)ColorConverter.ConvertFromString("#FFECF0F4"),0.16),
new GradientStop((Color)ColorConverter.ConvertFromString("#FFFCFCFD"),0.16),
new GradientStop((Color)ColorConverter.ConvertFromString("#FFFFFFFF"),1),
});
NumForeground = new SolidColorBrush(Colors.Black);
// DayForeground = new SolidColorBrush(Colors.Black);
}
// , Brush __DayForeground
public SelectDayElemet(int __num, Brush __Background, Brush __NumForeground)
{
_NUM = __num;
Background = __Background;
NumForeground = __NumForeground;
// DayForeground = __DayForeground;
}
//, string __StrDayForeground
public SelectDayElemet(int __num, string __StrBackground, string __StrForeground)
{
_NUM = __num;
Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(__StrBackground));
NumForeground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(__StrForeground));
// DayForeground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(__StrDayForeground));
}
int _NUM;
public int NUM
{
get { return _NUM; }
set {
_NUM = value;
OnPropertyChanged(()=>NUM);
}
}
Brush _Background;
public Brush Background
{
get { return _Background; }
set {
_Background = value;
OnPropertyChanged(()=>Background);
}
}
Brush _NumForeground;
public Brush NumForeground
{
get { return _NumForeground; }
set {
_NumForeground = value;
OnPropertyChanged(()=>NumForeground);
}
}
BindingProxy классная штука откуда стянул привожу
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace MonthCalendar.Helpers
{
/**
* @brief Прокси класс для доступа к данным
* взято с https://social.technet.microsoft.com/wiki/contents/articles/31422.wpf-passing-a-data-bound-value-to-a-validation-rule.aspx
*
*/
public class BindingProxy : System.Windows.Freezable
{
/**
* @brief Согласно требованиям "необходимо переопределить подкласс CreateInstanceCore метод" переопределяем
*/
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
/**
* @brief объект данных который будем "биндить"
*/
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
/**
* @brief Создаем DependencyProperty с именем "Data"
*/
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata(null));
}
}
конвенторы я не смог придумать лучшего способа чем мультибиндинг
using MonthCalendar.Helpers;
using MonthCalendar.Model;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
namespace MonthCalendar.Converters
{
public class NumberDateConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
try
{
if ((values[0] == null) || (values[1] == null)) return DependencyProperty.UnsetValue;
if ((values[0] == DependencyProperty.UnsetValue) || (values[1] == DependencyProperty.UnsetValue)) return DependencyProperty.UnsetValue;
var targetDate = (DateTime)values[0];
var SelectedDays = (Dictionary<DateTime, SelectDayElemet>)values[1];
try
{
SelectDayElemet val = null;
var res = SelectedDays.TryGetValue(targetDate, out val);
if (res)
return val.NUM.ToString();//parent.SelectedDays[targetDate].ToString();
else
return DependencyProperty.UnsetValue;
}
catch (Exception ex)
{
return DependencyProperty.UnsetValue;
}
}
catch (Exception ex)
{
return DependencyProperty.UnsetValue;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Пишу аналог кассового терминала для WindowsДля оплаты используются наличные или карта
Использую php-amqplib/rabbitmq-bundle Все работает нормально до момента пока Rabbit не обваливаетсяВопрос: как можно избежать этих ошибок
Возникла проблема, нужно сделать проверку на заглавные буквы в URL и переадресовывать на URL со строчными буквамиРеализация простая:
Возможно ли указать для $to: значение, которое пользователь ввел в инпуте Email? Чтобы письмо пришло на почту, которую пользователь указал в форме