DatePicker Template, Binding to SelectedDate not Working - c#

I'm trying to change the DatePicker template. I almost made the design with the help of Custom Control. But not only did I spend 2 days of my life on this, it also does not work incorrectly. The SelectedDateChenged call change event is called multiple times. I decided to change the approach, rewrite the template. Now there was a problem that Binding does not work. That is, there are changes in the calendar. I see them, the event is called, the SelectedDate changes there, but the Binding does not work. Please help me figure it out, I'm attaching the source code of the template and converters.
DatePicker Template
<Style x:Key="DatePickerStyle" TargetType="{x:Type DatePicker}">
<Style.Resources>
<conv:MonthToGenitiveMonthNameConverter x:Key="MonthToGenitiveMonthNameConverter"/>
<conv:MonthToAbbreviatedMonthNameConverter x:Key="MonthToAbbreviatedMonthNameConverter"/>
<conv:DayToDayNameConverter x:Key="DayToDayNameConverter"/>
<conv:DateToTwoDigitDateConverter x:Key="DateToTwoDigitDateConverter"/>
</Style.Resources>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Height" Value="70"/>
<Setter Property="Width" Value="500"/>
<Setter Property="IsTodayHighlighted" Value="True"/>
<Setter Property="SelectedDateFormat" Value="Short"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DatePicker}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<Grid x:Name="PART_Root" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid HorizontalAlignment="Stretch">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding Foreground}" FontSize="50" Text="{Binding Path=SelectedDate.Day, Converter={StaticResource DateToTwoDigitDateConverter}}" />
<StackPanel Margin="10,2,0,2" VerticalAlignment="Center" >
<TextBlock Foreground="{TemplateBinding Foreground}" FontSize="24" FontWeight="Bold" Text="{Binding Path=SelectedDate.Month, Converter={StaticResource MonthToGenitiveMonthNameConverter}}"/>
<TextBlock Foreground="{TemplateBinding Foreground}" FontSize="14" Text="{Binding Path=SelectedDate.DayOfWeek, Converter={StaticResource DayToDayNameConverter}}"/>
</StackPanel>
<TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding Foreground}" FontSize="50" Text="{Binding Path=SelectedDate.Year}" />
<TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding Foreground}" FontSize="50" Text="г." />
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Name="PART_Button" Style="{StaticResource ExtendedDataPickerButtonStyle}">
<fa:IconImage Icon="Calendar" Style="{StaticResource BigIconStyle}"/>
</Button>
<DatePickerTextBox x:Name="PART_TextBox" Visibility="Collapsed"/>
<Popup x:Name="PART_Popup" AllowsTransparency="True" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_Button}" StaysOpen="False"
ui:PopupProperties.HorizontalPlacementAlignment="Center"
ui:PopupProperties.VerticalOffset="2"/>
</StackPanel>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Converters
[ValueConversion(typeof(string), typeof(int))]
class DateToTwoDigitDateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int val = (int)value;
if (((int)val / 10) > 0)
{
return value.ToString();
}
else
{
return "0" + value.ToString();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[ValueConversion(typeof(string), typeof(DayOfWeek))]
class DayToDayNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return culture.DateTimeFormat.GetDayName((DayOfWeek)value).FirstCharToUpper();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[ValueConversion(typeof(string), typeof(int))]
class MonthToAbbreviatedMonthNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return culture.DateTimeFormat.GetAbbreviatedMonthName((int)value).FirstCharToUpper();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[ValueConversion(typeof(string), typeof(int))]
class MonthToGenitiveMonthNameConverter : IValueConverter
{
private const int ArrayZeroBasedConst = 1;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return culture.DateTimeFormat.MonthGenitiveNames[(int)value - ArrayZeroBasedConst].FirstCharToUpper();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[ValueConversion(typeof(string), typeof(int))]
class MonthToNominativeMonthNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return culture.DateTimeFormat.GetMonthName((int)value).FirstCharToUpper();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I don't know what to try anymore.
The code from this site, for which many thanks, I have already checked, just in case, it's not in it.
ui:PopupProperties.HorizontalPlacementAlignment="Center"
ui:PopupProperties.VerticalOffset="2"
I am trying to remake DatePicker and Calendar. I don't have access to the Internal methods in the source code, and there are quite a few of them. I can publish the source codes of the last iteration of programming, but it turned out to be a very large heap with truncated functionality.

I still solved this problem. I will not publish the entire code, I will publish only significant changes.
Firstly, Custom Control appeared again, only very minimalistic.
public class ModernDatePicker : DatePicker, IDisposable
{
public static readonly DependencyProperty VisualizatedDateProperty = DependencyProperty.Register(nameof(VisualizatedDate), typeof(DateTime), typeof(ModernDatePicker),
new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public DateTime VisualizatedDate
{
get { return (DateTime)GetValue(VisualizatedDateProperty); }
set { SetValue(VisualizatedDateProperty, value); }
}
static ModernDatePicker()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ModernDatePicker), new FrameworkPropertyMetadata(typeof(ModernDatePicker)));
}
public ModernDatePicker()
{
Loaded += ModernDatePicker_Loaded;
SelectedDateChanged += ModernDatePicker_SelectedDateChanged;
}
private void ModernDatePicker_Loaded(object sender, RoutedEventArgs e)
{
if (this.SelectedDate == null)
{
SelectedDate = VisualizatedDate;
}
}
private void ModernDatePicker_SelectedDateChanged(object? sender, SelectionChangedEventArgs e)
{
ModernDatePicker mdp = (ModernDatePicker)sender;
if (mdp.SelectedDate != null)
{
VisualizatedDate = mdp.SelectedDate.Value;
}
}
}
public void Dispose()
{
SelectedDateChanged -= ModernDatePicker_SelectedDateChanged;
Loaded -= ModernDatePicker_Loaded;
}
SelectDate is a DateTime? type, which does not allow you to get the value immediately at startup, you had to use a DependencyProperty, with a DateTime type, in order to be able to use Binding.
Secondly, changes in XAML.
<Style TargetType="{x:Type cc:ModernDatePicker}">
<Style.Resources>
<conv:MonthToGenitiveMonthNameConverter x:Key="MonthToGenitiveMonthNameConverter"/>
<conv:DayToDayNameConverter x:Key="DayToDayNameConverter"/>
<conv:DateToTwoDigitDateConverter x:Key="DateToTwoDigitDateConverter"/>
</Style.Resources>
<Setter Property="Foreground" Value="#223266"/>
<Setter Property="IsTodayHighlighted" Value="True"/>
<Setter Property="CalendarStyle" Value="{DynamicResource ModernCalendarStyle}"/>
<Setter Property="SelectedDateFormat" Value="Short"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="SubForeground" Value="#9eabe2"/>
<Setter Property="OtherForeground" Value="White"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type cc:ModernDatePicker}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<Grid x:Name="PART_Root" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid HorizontalAlignment="Stretch">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding OtherForeground}" FontSize="50" Text="{Binding VisualizatedDate.Day, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}},Converter = {StaticResource DateToTwoDigitDateConverter}}" />
<StackPanel Margin="10,2,0,2" VerticalAlignment="Center" >
<TextBlock Foreground="{TemplateBinding OtherForeground}" FontSize="24" FontWeight="Bold" Text="{Binding VisualizatedDate.Month, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}}, Converter={StaticResource MonthToGenitiveMonthNameConverter}}"/>
<TextBlock Foreground="{TemplateBinding SubForeground}" FontSize="14" Text="{Binding VisualizatedDate.DayOfWeek, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}}, Converter={StaticResource DayToDayNameConverter}}"/>
</StackPanel>
<TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding OtherForeground}" FontSize="50" Text="{Binding VisualizatedDate.Year, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}}}" />
<TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding OtherForeground}" FontSize="50" Text="г." />
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Name="PART_Button" Style="{StaticResource ExtendedDataPickerButtonStyle}">
<fa:IconImage Icon="Calendar" Style="{StaticResource BigIconStyle}"/>
</Button>
<DatePickerTextBox x:Name="PART_TextBox" Visibility="Collapsed"/>
<Popup x:Name="PART_Popup" AllowsTransparency="True" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_Button}" StaysOpen="False"
ui:PopupProperties.HorizontalPlacementAlignment="Center"
ui:PopupProperties.VerticalOffset="2"/>
</StackPanel>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
Well, in fact, by analogy

Related

Set Background color of ItemsControl

In my WPF Application, I have Item control which shows Dates and Days of a week.
Now,I need to change the background color of the Item which is today's date.
Here is the XAML code
<ItemsControl Grid.Column="1"
Focusable="False"
ItemsSource="{Binding WeekDays}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate >
<DataTemplate>
<Border BorderBrush="{StaticResource GrayBrush7}"
BorderThickness="1,0,0,0"
SnapsToDevicePixels="True"
UseLayoutRounding="True">
<StackPanel Margin="2"
VerticalAlignment="Center">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Top"
Text="{Binding Day}"
TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Top"
Text="{Binding Date,
StringFormat='dd/MM/yyyy'}"
TextAlignment="Center"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Thanks in Advance.
You can use DataTrigger in Border Style if you have IsToday property in model class. Like this
public class WeekDay
{
public DateTime Date { get; }
public string Day { get; }
public bool IsToday { get; }
public WeekDay(DateTime date)
{
this.Date = date;
this.Day = date.DayOfWeek.ToString();
this.IsToday = date.Date == DateTime.Today;
}
}
<ItemsControl.ItemTemplate >
<DataTemplate>
<Border BorderBrush="{StaticResource GrayBrush7}"
BorderThickness="1,0,0,0"
SnapsToDevicePixels="True"
UseLayoutRounding="True">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding IsToday}" Value="True">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
...
As an alternative, you can use ValueConverter to convert Date to Background.
public class DateToItemBackgroundConverter : IValueConverter
{
private static readonly Brush TodayBGBrush = new SolidColorBrush(Colors.Yellow);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || !(value is DateTime))
{
return value;
}
var isToday = ((DateTime)value).Date == DateTime.Today;
return isToday ? TodayBGBrush : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<ItemsControl Grid.Column="1"
Focusable="False"
ItemsSource="{Binding WeekDays}">
<ItemsControl.Resources>
<local:DateToItemBackgroundConverter x:Key="bgConverter" />
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate >
<DataTemplate>
<Border BorderBrush="{StaticResource GrayBrush7}"
Background="{Binding Date, Converter={StaticResource bgConverter}}"
BorderThickness="1,0,0,0"
SnapsToDevicePixels="True"
UseLayoutRounding="True">
...
Remember if you wanna refresh background when TODAY is updated, you should rebuild model data or notify PropertyChanged again.
You could just add a Border style with a DataTrigger to your ItemTemplate. Compare the Date property of your DateTime property with the static DateTime.Today property:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="{StaticResource GrayBrush7}"
BorderThickness="1,0,0,0"
SnapsToDevicePixels="True"
UseLayoutRounding="True">
<Border.Style>
<Style TargetType="Border" xmlns:system="clr-namespace:System;assembly=mscorlib">
<Style.Triggers>
<DataTrigger Binding="{Binding Date.Date}" Value="{x:Static system:DateTime.Today}">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Margin="2"
VerticalAlignment="Center">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Top"
Text="{Binding Day}"
TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Top"
Text="{Binding Date, StringFormat='dd/MM/yyyy'}"
TextAlignment="Center"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>

Cross-binding checkboxes - isChecked #1 -> isEnabled #2

I have a ListBox that takes boolean elements from list in my model and represent them as checkboxes. Just after building project the second checkbox isEnabled is set to false. If I modify (eg. cut and paste same converter) binding in the second checkbox in debug, the binding start working correctly. Also I have a global checkboxes that modyfi isChecked properties of all checkboxes from listBox. If I set globalCheckbox #2, all listBox_checkBoxes #2 are set to true and all listBox_checkBoxes #1 isEnabled property are set to false
XAML:
<ListBox x:Name="ListBox_assent" SelectedIndex="-1" Grid.Row="2" ItemsSource="{Binding Path=FullDataAssetList.List}" IsSynchronizedWithCurrentItem="True" Height="Auto">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Setter Property="Margin" Value="2"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Focusable" Value="False" />
<EventSetter Event="RequestBringIntoView" Handler="ListBoxItem_RequestBringIntoView"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Grid.Row="0" Opacity="{Binding Path=SkipAssentTemp, Converter={StaticResource BoolToOpacity}}">
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="3">
<CheckBox x:Name="chbx_Assent" HorizontalContentAlignment="Left" FlowDirection="RightToLeft" ToolTip="Skip" IsChecked="{Binding SkipAssent, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding SkipAssentTemp, Converter={StaticResource InverseBoolean}}" LostFocus="chbx_Assent_LostFocus" Background="#FFCB0000"/>
<TextBlock FontSize="16" Text=" / " VerticalAlignment="Center"/>
<CheckBox x:Name="chbx_AssentTemp" HorizontalContentAlignment="Left" FlowDirection="RightToLeft" ToolTip="Skip temp." IsChecked="{Binding SkipAssentTemp, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding SkipAssent, Converter={StaticResource InverseBoolean}}" LostFocus="chbx_AssentTemp_LostFocus" Background="#FFCBA300"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Converter:
public class InverseBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType == typeof(bool) || targetType == typeof(bool?))
{
if ((bool?)value == true)
{
return false;
}
else
if ((bool?)value == false)
{
return true;
}
return null;
}
else
{
throw new InvalidOperationException("The target must be a boolean");
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
How can i fix binding to get full functionality just after building?
I have found solution. DataTrigger in xaml was overwritnig isEnabled property

Access element from style WPF

I have a style declared in a ResourceDictionary like so.
<Style x:Key="MapMarkerLabelStyle" TargetType="{x:Type TextBlock}">
<Setter Property="RenderTransform">
<Setter.Value>
<TranslateTransform X="{Binding ActualWidth,
Converter={StaticResource DoubleMultiplierConverter},
ConverterParameter=-0.5}"
Y="-62"></TranslateTransform>
</Setter.Value>
</Setter>
</Style>
And the textblock
<TextBlock Style="{StaticResource MapMarkerLabelStyle}" />
And the converter:
public class DoubleMultiplierConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var originalValue = (double) value;
var format = new NumberFormatInfo {NumberDecimalSeparator = "."};
var multiplier = System.Convert.ToDouble(parameter, format);
return originalValue * multiplier;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
In the translate transform i need to access the textblock ActualWidth property but cant figure out how the binding should look.
The Binding is missing an appropriate source object. To bind to the TextBlock's ActualWidth property, you should set the RelativeSource like this:
<Style x:Key="MapMarkerLabelStyle" TargetType="TextBlock">
<Setter Property="RenderTransform">
<Setter.Value>
<TranslateTransform
X="{Binding Path=ActualWidth,
RelativeSource={RelativeSource AncestorType=TextBlock}
Converter={StaticResource DoubleMultiplierConverter},
ConverterParameter=-0.5}"
Y="-62"/>
</Setter.Value>
</Setter>
</Style>
Try this.
<TranslateTransform X="{Binding RelativeSource={RelativeSource Self},
Path=ActualWidth,
Converter={StaticResource DoubleMultiplierConverter},
ConverterParameter=-0.5}"
Y="-62">
</TranslateTransform>

dependency property in custom control not updating

I'm trying to make a custom control which is basically a TextBox that sits above a datagrid column header and displays the total number in the datagrid column. The control library consists of two custom-controls: DataGridColumnTotal contains the textbox, which also holds references to the DataGrid and ItemsSource. The other is called DataGridHeaderTotalControl, which is basically a style that targets the DataGridColumnHeader. This style places the DataGridColumnTotal control above the existing DatagridColumnHeader and binds the DataGrid and DataGridItemsSource fields from the DataGridColumnTotal control to the Datagrid and ItemsSource fields.
I'm currently just trying to get the TextBox to show if the IsTotalVisible dependency property is set, but it will not update when I try to set it in MainWindow.xaml. I don't have any code in place that displays the total value because I haven't gotten that far yet.
The problem occurs in MainWindow.xaml, when trying to set ctl:DataGridColumnTotal.IsTotalVisible="True" in the dataGridText column. The IsTotalVisible property is not getting set to true. But when I set the default value of the dependency property to true, the total textboxes will show.
DataGridColumnTotal.cs
////////////////////////////////////////////////////////////////////
//DataGridColumnTotal.cs
////////////////////////////////////////////////////////////////////
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Collections;
namespace RiskControlLibrary
{
public class DataGridColumnTotal : Control
{
static DataGridColumnTotal()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DataGridColumnTotal), new FrameworkPropertyMetadata(typeof(DataGridColumnTotal)));
}
public static bool GetIsTotalVisible(
DependencyObject target)
{
return (bool)target.GetValue(IsTotalVisibleProperty);
}
public static void SetIsTotalVisible(
DependencyObject target, bool value)
{
target.SetValue(IsTotalVisibleProperty, value);
}
public static DependencyProperty IsTotalVisibleProperty =
DependencyProperty.RegisterAttached("IsTotalVisible", typeof(bool), typeof(DataGridColumnTotal),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
}
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((bool)value)
return Visibility.Visible;
else
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new Exception("Not Implemented.");
}
}
}
DataGridHeaderTotalControl.cs
////////////////////////////////////////////////////////////////////
//DataGridHeaderTotalControl.cs
////////////////////////////////////////////////////////////////////
using System.Windows;
using System.Windows.Controls;
namespace RiskControlLibrary
{
public class DataGridHeaderTotalControl : Control
{
static DataGridHeaderTotalControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DataGridHeaderTotalControl), new FrameworkPropertyMetadata(typeof(DataGridHeaderTotalControl)));
}
}
}
Generic.xaml
////////////////////////////////////////////////////////////////////
//Generic.xaml
////////////////////////////////////////////////////////////////////
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RiskControlLibrary"
xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:s="clr-namespace:System;assembly=mscorlib">
<Style TargetType="{x:Type local:DataGridColumnTotal}">
<Style.Resources>
<local:BoolToVisibilityConverter x:Key="booleanToVisibilityConverter" />
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DataGridColumnTotal}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBox
x:Name="PART_TextBoxTotal"
IsReadOnly="True"
VerticalAlignment="Top"
VerticalContentAlignment="Center"
Text="{Binding Total,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:DataGridColumnTotal}}}"
Visibility="{Binding IsTotalVisible, RelativeSource={RelativeSource TemplatedParent},
Converter={StaticResource booleanToVisibilityConverter}}"
>
</TextBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type DataGridColumnHeader}"
x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:DataGridHeaderTotalControl},
ResourceId=DataGridHeaderTotalControlStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<local:DataGridColumnTotal Margin="1" Grid.Column="0" Grid.Row="0"/>
<theme:DataGridHeaderBorder Grid.Column="0" Grid.Row="1" SortDirection="{TemplateBinding SortDirection}"
IsHovered="{TemplateBinding IsMouseOver}"
IsPressed="{TemplateBinding IsPressed}"
IsClickable="{TemplateBinding CanUserSort}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding ="{TemplateBinding Padding}"
SeparatorVisibility="{TemplateBinding SeparatorVisibility}"
SeparatorBrush="{TemplateBinding SeparatorBrush}">
<TextBlock Grid.Column="0" Grid.Row="1" Text="{TemplateBinding Content}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
TextWrapping="Wrap"></TextBlock>
</theme:DataGridHeaderBorder>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainWindow.xaml
////////////////////////////////////////////////////////////////////
//MainWindow.xaml
////////////////////////////////////////////////////////////////////
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication1"
xmlns:ctl="clr-namespace:RiskControlLibrary;assembly=RiskControlLibrary"
Title="MainWindow" Height="341" Width="452"
Loaded="Window_Loaded">
<Grid>
<DataGrid
Name="m_dgOrder"
ItemsSource="{Binding ListPos}"
GridLinesVisibility="None"
AutoGenerateColumns="False"
IsReadOnly="True"
Background="White"
CanUserResizeRows="False"
HeadersVisibility="Column"
RowHeaderWidth="0"
ColumnHeaderStyle="{StaticResource {ComponentResourceKey
TypeInTargetAssembly={x:Type ctl:DataGridHeaderTotalControl},
ResourceId=DataGridHeaderTotalControlStyle}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Symbol" Binding="{Binding Path=Symbol}"/>
<DataGridTextColumn Header="Pos" Binding="{Binding Path=Pos}" ctl:DataGridColumnTotal.IsTotalVisible="True"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
I was registering the IsTotalVisible property to the wrong class. Instead of DataGridColumnTotal it should've been DataGridTextColumn.

Changing source of an Image inside of a Button template

I have a button with an image defined in XAML like this:
<Button x:Name="buttonTest">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" >
<Image x:Name="imageTest" Width="57" Height="81" Source="/Images/sample.png" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
How can I change the source of the image when the button is clicked?
I would probably do this with a toggle button instead of button since it has the IsChecked property that you can base the image switch on.
First you'll need some converter to go from true/false to the image path, may as well make it a generic one that you can use over and over, add this to your project and setup an xmlns to point to it in your xaml.
public class BooleanSwitchConverter : DependencyObject, IValueConverter
{
public object TrueValue
{
get { return (object)GetValue(TrueValueProperty); }
set { SetValue(TrueValueProperty, value); }
}
public static readonly DependencyProperty TrueValueProperty =
DependencyProperty.Register("TrueValue", typeof(object), typeof(BooleanSwitchConverter), new PropertyMetadata(null));
public object FalseValue
{
get { return (object)GetValue(FalseValueProperty); }
set { SetValue(FalseValueProperty, value); }
}
public static readonly DependencyProperty FalseValueProperty =
DependencyProperty.Register("FalseValue", typeof(object), typeof(BooleanSwitchConverter), new PropertyMetadata(null));
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? TrueValue : FalseValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then replace your Button with a toggle button like this using a Binding on IsChecked to pick the image.
<ToggleButton>
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border>
<Image>
<Image.Source>
<Binding Path="IsChecked" RelativeSource="{RelativeSource TemplatedParent}">
<Binding.Converter>
<local:BooleanSwitchConverter
TrueValue="1.jpg"
FalseValue="2.jpg"/>
</Binding.Converter>
</Binding>
</Image.Source>
</Image>
</Border>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
You can use a trigger like this (Used a rectangle for simplicity in the sample):
<Button x:Name="buttonTest" Width="200" Height="200">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center" >
<Rectangle x:Name="Image" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" Fill="Yellow"></Rectangle>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Image" Property="Fill" Value="Red"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
So I finally figured it out, user Gambi provided an answer in another thread.

Categories

Resources