Why is 'StringFormat' malfunctioning?
About Data Type
If you are binding a string
value to text property of TextBlock
or TextBox
, then append StringFormat
, it will work.
For example: <TextBlock Text="{Binding StringValue, StringFormat={} I am special: {0}}" />
Otherwise, let's say if there's a object
value is bound to text, it won't work at all. In this situation, you need a Converter
to solve.
Decimal Type
If you are binding a string
value to text property and the StringFormat
is like: {}{0:N0}
(formatted number), it won't work either. This also won't work in c# code like string.Format("{0:n0}", value)
(if value is astring
)
Why does my UI text blurry after apply DropShadowEffect?
- Solution 1: Separate
Control
which appliedDropShadowEffect
from your textControl
. - Solution 2: Add
RenderingBias="Quality"
attribute toDropShadowEffect
. See ref - Solution 3:
DropShadowEffect
may cause performance issue, trySystemDropShadowChrome
instead:- Add reference to project:
PresentationFramework.Aero
- Add using:
xmlns:dropShadow="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
- Add reference to project:
How to debug codes in design mode?
Here are the steps to debug a control at design time:
Start a second instance of Visual Studio
Attach to the first instance(vs designer is called XDesProc.exe
) from the Debug menu
In the second instance, open the source code of your control
Set breakpoints at appropriate locations
In the first VS instance, reload the designer
Note that this technique isn't limited to controls; you can also use it to debug VS extensions, or anything that executes within Visual Studio.
How to binding control events to commands
<i:Interaction.Triggers>
<i:EventTrigger EventName="OnLoaded">
<i:EventTrigger.Actions>
<i:InvokeCommandAction Command="{Binding MyCommand}"></i:InvokeCommandAction>
</i:EventTrigger.Actions>
</i:EventTrigger>
</i:Interaction.Triggers>
How to use async command execute
private async void MyCommandExecute()
{
IsBusy = true;
var models = await Task.Run(() =>
{
return GetDataFromServer();
});
IsBusy = false;
}
or in a better way, encapsulate DoWork
method in ViewModelBase
:
ViewModelBase.cs
rprc IsBusy;
public async void DoProgressAsync<TResult>(Func<TResult> workFunc, Action<TResult> callbackAction)
{
IsBusy = true;
var result = await Task.Run(workFunc);
callbackAction(result);
IsBusy = false;
}
Events for Switch TextBlock to TextBox when mousedown
Here is fields and properties in the custom control we need: _isMouseDown
; IsEditMode
(dependency property)
public override void OnApplyTemplate()
{
_textblock.PreviewMouseLeftButtonDown += delegate { _isMouseDown = true; };
_textblockv.PreviewMouseLeftButtonUp += delegate {
if(_isMouseDown) {
IsEditMode = true;
Keyboard.Focus(_textBox);
_isMouseDown = false;
}
};
_label.GotKeyboardFocus += delegate{
//same as left button up
};
_textBox.LostKeyboardFocus += delegate {
IsEditMode = false;
};
}
Simple Loading Ellipse
<ControlTemplate x:Key="LoadingControlTemplate">
<Ellipse StrokeThickness="2" Width="12" Height="12" RenderTransformOrigin="0.5 0.5" ToolTip="{TemplateBinding ToolTip}" Name="el">
<Ellipse.Stroke>
<RadialGradientBrush GradientOrigin="0.2 0" Center="0.5 0.9" RadiusX="0.75" RadiusY="0.5">
<GradientStop Color="Transparent" Offset="1" />
<GradientStop Color="White" Offset="0.35" />
</RadialGradientBrush>
</Ellipse.Stroke>
<Ellipse.RenderTransform>
<RotateTransform Angle="0" />
</Ellipse.RenderTransform>
</Ellipse>
<ControlTemplate.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard Name="ani">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Ellipse.RenderTransform).(RotateTransform.Angle)"
Storyboard.TargetName="el"
To="360" Duration="0:0:0.75" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="ani"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Solid color style ProgressBar
for Indeterminate
<!--Please use Foreground as Indicator color-->
<ControlTemplate x:Key="IndeterminateProgressBar" TargetType="{x:Type ProgressBar}" >
<Grid MinHeight="2" MinWidth="150" Name="TemplateRoot" SnapsToDevicePixels="True" >
<Rectangle RadiusX="2" RadiusY="2" Fill="Transparent" />
<Border CornerRadius="0" Margin="1">
<Border.Background>
<SolidColorBrush Color="Transparent"/>
</Border.Background>
</Border>
<Border BorderThickness="0" BorderBrush="Transparent" Margin="1">
<Border.Background>
<SolidColorBrush Color="Transparent"/>
</Border.Background>
</Border>
<Rectangle Name="PART_Track" Margin="1" />
<Decorator Name="PART_Indicator" Margin="1" HorizontalAlignment="Left">
<Grid Name="Foreground">
<Rectangle Fill="Transparent" Name="Indicator" />
<Grid Name="Animation" ClipToBounds="True">
<Border Name="PART_GlowRect" Width="80" Margin="0,0,0,0" HorizontalAlignment="Left" Background="{TemplateBinding Foreground}"/>
</Grid>
<Grid Name="Overlay">
</Grid>
</Grid>
</Decorator>
<Border BorderThickness="0" CornerRadius="0" BorderBrush="Transparent" />
</Grid>
</ControlTemplate>
for Determinate
<!--Please use Foreground as Indicator color, Background as TotalWidth background-->
<ControlTemplate x:Key="DeterminateProgressBar" TargetType="{x:Type ProgressBar}">
<Grid MinHeight="2" MinWidth="150" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Border x:Name="PART_Track" BorderThickness="0">
</Border>
<Border x:Name="PART_Indicator" BorderThickness="0" HorizontalAlignment="Left" Background="{TemplateBinding Foreground}" Margin="0">
</Border>
</Grid>
</ControlTemplate>
Usage
<ProgressBar Template="{StaticResource IndeterminateProgressBar}" IsIndeterminate="True" Foreground="LightBlue"
Visibility="{Binding IsRefreshing, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<ProgressBar Template="{StaticResource DeterminateProgressBar}" Minimum="0" Maximum="{Binding ItemCount}" Value="{Binding CurrentItemIndex}" Foreground="Red" Background="Green"
Visibility="{Binding IsLoadingFinished, Converter={StaticResource BooleanToVisibilityConverter}}"/>
**for 30 seconds pending progress
A little trick using rectangle by scale animation rather than ProgressBar
with Timer
:
<Style x:Key="PendingProgressRect" TargetType="Rectangle">
<Setter Property="Height" Value="1"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="0"></ScaleTransform>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard Name="pendingProgressAni">
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="RenderTransform.ScaleX"
Duration="0:0:30" Timeline.DesiredFrameRate="1">
<DiscreteDoubleKeyFrame Value="0.1" KeyTime="0:0:3" />
<DiscreteDoubleKeyFrame Value="0.2" KeyTime="0:0:6" />
<DiscreteDoubleKeyFrame Value="0.3" KeyTime="0:0:9" />
<DiscreteDoubleKeyFrame Value="0.4" KeyTime="0:0:12" />
<DiscreteDoubleKeyFrame Value="0.5" KeyTime="0:0:15" />
<DiscreteDoubleKeyFrame Value="0.6" KeyTime="0:0:18" />
<DiscreteDoubleKeyFrame Value="0.7" KeyTime="0:0:21" />
<DiscreteDoubleKeyFrame Value="0.8" KeyTime="0:0:24" />
<DiscreteDoubleKeyFrame Value="0.9" KeyTime="0:0:27" />
<DiscreteDoubleKeyFrame Value="1.0" KeyTime="0:0:29.7" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="pendingProgressAni"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
AddSorted to List/Collection
/// <summary>
/// Adds a new item with sorted by comparer in the collection.
/// </summary>
public static void AddSorted<T>(this IList<T> list, T item, IComparer<T> comparer = null)
{
var comparerPara = comparer;
if (comparerPara == null)
comparerPara = Comparer<T>.Default;
int i = 0;
while (i < list.Count && comparerPara.Compare(list[i], item) < 0)
{
i++;
}
//you may want to invoke this on UI thread if context is at background.
list.Insert(i, item);
}
Then any model which has IComparable<T>
implemented will take effect in this extension method.