C# UWP Template10.Validation Change Style - c#

With "Template10.Validation", I want to change style.
First I made this Style for "validate:ControlWrapper".
<Style TargetType="validate:ControlWrapper">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="validate:ControlWrapper">
<StackPanel>
<ContentPresenter Content="{TemplateBinding Content}" />
<ItemsControl ItemsSource="{Binding Errors, Source={TemplateBinding Properties[PropertyName]}}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="Red" Text="{Binding}" Visibility="{Binding IsValid}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and Here is the result.
Something is strange. because I want to display Validation warning message for ONLY first name. but It display every warning. from address, from postal code.
My main quesiton
How to access "ValidatableModelBase.Property["PropertyName"].Errors" in Xaml.
because [] branket is not possible to use in XAML binding. How to accesss ??

with lot of my time, I finally find a solution for my own question...
First is my model class.
public class SettingEmail
: Template10.Validation.ValidatableModelBase
{public string EmailReceivers { get { return Read<string>(); } set { Write(value); } }}
Next is Property to bind. ( in my ViewModel class )
public SettingEmail SettingEmailModel{ get { return se; } set { this.Set(ref se, value); } }
Next is XAML code.
<validate:ControlWrapper DataContext="{Binding SettingEmailModel}"
PropertyName="EmailReceivers"
Style="{StaticResource validationNotify}">
<TextBox Text="{Binding EmailReceivers, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MinHeight="400" Style="{StaticResource SettingStyle_MultilineTextBox}"/>
</validate:ControlWrapper>
and Last is Style in Resource file.
<Style x:Key="validationNotify" TargetType="validate:ControlWrapper">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="validate:ControlWrapper">
<StackPanel >
<ContentPresenter Content="{TemplateBinding Content}"/>
<ItemsControl DataContext="{TemplateBinding Property}"
ItemsSource="{Binding Errors, Source={TemplateBinding Property}}"
Style="{StaticResource validationNotifyMessage}"
>
<ItemsControl.ItemTemplate >
<DataTemplate>
<StackPanel>
<TextBlock Foreground="Red" Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I hope it help someone.
and I am sorry with my poor question's descriptions...I will try improve next...

Related

How can I change the direction in which children are added to a wrapPanel?

I have a WrapPanel which is the parent of many TextBlock in an ItemsControl.
Each TextBlock displays a word in Arabic, and the whole forms a sentence. To display the sentence, I put in my Binding List to the ItemsControl the words in the order they are in an Arabic reading (from right to left).
public UserControl_ArabicVerseSelectable(List<WordInVerse> wordsInVerse)
{
InitializeComponent();
List<WordsOfUC> items = new List<WordsOfUC>();
foreach (WordInVerse word in wordsInVerse)
{
items.Add(new WordsOfUC() { Arabic = word.Arabic, WordID = word.WordID });
}
items.Reverse();
ItemControl_Words.ItemsSource = items;
}
WPF:
<ItemsControl x:Name="ItemControl_Words"
HorizontalAlignment="Center"
Margin="0,10,0,0" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical"
Margin="5,0,5,0">
<TextBlock Tag="{Binding WordID}"
x:Name="textBlock_arabic"
Text="{Binding Arabic}"
FontSize="40"
HorizontalAlignment="Center"
FontFamily="Noto Naskh Arabic"
Cursor="Hand"
MouseDown="textBlock_arabic_MouseDown"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
That is to say:
...word3, word2, word1
The problem is that when the sentence is only one line long in the wrapPanel, it displays very well:
But as soon as the sentence is two lines long...
The last line should be above the first, as it is the beginning of the sentence, but since the words are added from right to left, first the first line fills and then only the second.
So is there any way to add children to the WrapPanel from right to left, or if not, is there any way to reverse all the lines in a WrapPanel?
Add The "FlowDirection" Style Triggers to your TextBlock
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="5,0,5,0">
<TextBlock Tag="{Binding WordID}" x:Name="textBlock_arabic" Text="{Binding Arabic}" FontSize="40" HorizontalAlignment="Center"
FontFamily="Noto Naskh Arabic" Cursor="Hand"
MouseDown="textBlock_arabic_MouseDown">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="FlowDirection"
Value="RightToLeft">
<Setter Property="TextAlignment"
Value="Right" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
NOTE: I took this of a project a long time ago.

WPF c# setting style with parameters

I'm looking for a way to assign style with parameters(most of them just text) and assign to specified blocks
<StackPanel Orientation="Horizontal">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="field1" Text="Field1"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Default" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="field2" Text="Field2"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="RCC" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="field3" Text="Field3"/>
</StackPanel>
</StackPanel>
<Rectangle Width="1" Fill="Black" Height="42" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal">
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Custom" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<TextBox Width="90" Height="15"/>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Apply" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
</StackPanel>
</StackPanel>
There is 3 TextBlocks(field1,field2,field3), now is there any way to pass parameters(parameters are string type), to this template, and this template is generated through loop. And how to do it? Of course I could make everything in c# but thought it would be much easier just create field(stackpanel) and assign parameters
<stackpanel Style="{StaticResource mystyle}" param1="hello" param2="this" param3="world"/>
This would be perfect if its possible to make this way. Unless there is better one. Thanks for help.
You can by declaring your own Styles and Control templates with additional use of DependencyProperties.
A DependencyProperty is basically a declaration on your own custom class of your own custom property that you want to expose available during xaml entry and can also be applied to your style templates.
Once that is done, you then define your style, plenty of resources on that. Include your dependency properties as {TemplateBinding} to your custom properties.
Then add instance of your new class to your form, and specify which style to use. I have a sample showing utilization of TWO styles under the same class. I first started with a brand new WPF application. In the MainWindow.xaml.cs, I defined my own class based on a type of UserControl (which can then hold any other control(s) such as you have nested). I added 3 Dependency Properties to reflect 3 possible text values you want to implement.
public class MyControl : UserControl
{
public static readonly DependencyProperty MyText1Property =
DependencyProperty.Register("MyText1", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText1
{
get { return (string)GetValue(MyText1Property); }
set { SetValue(MyText1Property, value); }
}
public static readonly DependencyProperty MyText2Property =
DependencyProperty.Register("MyText2", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText2
{
get { return (string)GetValue(MyText2Property); }
set { SetValue(MyText2Property, value); }
}
public static readonly DependencyProperty MyText3Property =
DependencyProperty.Register("MyText3", typeof(string),
typeof(MyControl), new UIPropertyMetadata(""));
public string MyText3
{
get { return (string)GetValue(MyText3Property); }
set { SetValue(MyText3Property, value); }
}
}
Next, my application name is StackOverflow for sample purposes, and in the following is the entire MainWindow.xaml. Clarification of components follows code.
<Window.Resources>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding MyText1}"/>
<TextBlock Text="{TemplateBinding MyText2}"/>
<TextBlock Text="{TemplateBinding MyText3}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock Text="{TemplateBinding MyText1}"/>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Default" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{TemplateBinding MyText2}"/>
</StackPanel>
</StackPanel>
<StackPanel>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="RCC" Foreground="#FFCFCFCF" Margin="0" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="{TemplateBinding MyText3}"/>
</StackPanel>
</StackPanel>
<Rectangle Width="1" Fill="Black" Height="42" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal">
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Custom" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
<TextBox Width="90" Height="15"/>
<Button BorderThickness="0">
<Button.Content>
<Border CornerRadius="18" BorderThickness="1" BorderBrush="#FFCFCFCF" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="10" Text="Apply" Foreground="#FFCFCFCF" FontWeight="Black"/>
</StackPanel>
</Border>
</Button.Content>
</Button>
</StackPanel>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- NOW, we can expand the custom properties-->
<Style TargetType="{x:Type myApp:MyControl}" BasedOn="{StaticResource MyControlStyle}" />
</Window.Resources>
<Grid Height="150">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<myApp:MyControl MyText1="First String" MyText2="Second String" MyText3="Third String"
Style="{StaticResource MyControlStyle}"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="1"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="2"
Style="{StaticResource MyControlStyle1}"/>
</Grid>
At the top within the main declaration, I added
xmlns:myApp="clr-namespace:StackOverflow"
this basically states that when within this xaml file, I see a prefix of "myApp", it is similar to a "using StackOverflow;" command as if in code. So now I have access to the custom class(es) or other things within that namespace to the xaml.
Next I start to declare my own "style" for the custom MyControl class via
<Window.Resources>
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp:MyControl}" >
...
You might want to create a separate ResourceDictionary if you deal with many styles / templates used throughout your app. Notice the "Syle" and custom "ControlTemplate" are based on the "myApp:MyControl" class structure. Now, I can make use of my "MyText1", "MyText2", "MyText3" elements within the control template.
The x:Key="MyControlStyle1" is like creating a variable by given name so it can be used if you need to explicitly say which style to use. This first style is just to show the point that the 3 "MyText" properties are available and the Text is getting its value from the
Text="{TemplateBinding MyText1}"
Class that the control template is bound to (hence TemplateBinding).
Once you get the basics working, then you can glorify your template as you have with your nested stack panels which is the lower
<Style TargetType="{x:Type myApp:MyControl}" x:Key="MyControlStyle">
declaration by a different x:Key name.
Now, so you don't have to explicitly keep adding xaml for your control and say... by the way, use this explicit style of MyControlStyle, I have the following
<Style TargetType="{x:Type myApp:MyControl}" BasedOn="{StaticResource MyControlStyle}" />
indicating whenever you see a target type of "MyControl", default the style to the "MyControlStyle" so I don't have to keep remembering to do it.
Finally implementing its use. The end of the code has a simple Grid control with 3 rows.
<myApp:MyControl MyText1="First String" MyText2="Second String" MyText3="Third String"
Style="{StaticResource MyControlStyle}"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="1"/>
<myApp:MyControl MyText1="Another Line" MyText2="diff string" MyText3="all done" Grid.Row="2"
Style="{StaticResource MyControlStyle1}"/>
Notice the first instance I CAN explicitly declare the style to be used. The second has no explicit style as per the default, but the third instance explicitly states to use the simplified "MyControlStyle1" which was just the 3 textblocks side-by-side showing that you can have one class and make it look differently as needed.
Revision per questions/comments.
If you are building these controls based on a loop and dynamically adding them, you would just set the properties respectively in the code. Performance should not be significant because the CLASS is already declared, you are just adding one more into your list.
foreach( var oneThing in YourListOfToBeAddedItems )
{
var mc = new MyControl();
mc.MyText1 = oneThing.TextFieldUsedForField1;
mc.MyText2 = oneThing.FieldForSecondText;
mc.MyText3 = oneThing.ThirdTextBasisForDisplay;
// Now, add the "mc" to whatever your control is
// can't confirm this line below as I dont know context
// of your form and dynamic adding.
YourWindowGridOrOtherControl.Controls.Add( mc );
}
Also, since the default style was defined, I would not need to explicitly declare the "Style" for the control.

How to change XAML elemen't template from code-behind?

I have next button's style defined in resources:
<Style x:Key="OKBtn" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle .../>
<TextBlock x:Name="Text" ..>
<Run Language="en-en" Text="OK"/>
</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I want in some specified case from code change Button's text.
I.e. change "OK" (<Run Language="en-en" Text="OK"/>) to "Accept".
How can I do that?
Is it possible to access this TextBlock "Text" and change content exactly for my one button, but not for all OK buttons?
My button:
<Button x:Name="OkButton" Style="{DynamicResource OKBtn}" />
You can borrow some props from template Template, for example Tag property. So the TextBlock text in the ControlTemplate should be like this.
<Run Language="en-en" Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Tag}"/>
And you can change the button caption by setting it's Tag property.
OkButton.Tag = "Accept";
And for not set all button texts manually you can create some ValueConverter to set TextBlock text in the ControlTemplate to the "Ok" whenever Tag property is empty.
At first, you should declare ContentPresenter to show any object in your Content property of Button control.
<Style x:Key="OkBtn" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle/>
<ContentPresenter Content="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></ContentPresenter>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Then, it is possible to set another Content by using code behind or binding:
By code behind:
okButton.Content="desirableText";
By binding:
<Button x:Name="OkButton" Style="{DynamicResource OKBtn}" Content="{Binding FooText}" />
private string fooText;
public string FooText
{
get { return fooText; }
set
{
fooText = value;
OnPropertyChanged("FooText");
}
}

Access a control from within a DataTemplate with its identifying name

In my WPF application I have a ComboBox control that is located inside a Grid Control. In XAML I am assigning a name to the ComboBox:
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center" Text="{Binding name_ru}" Width="Auto" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="stcom" Style="{DynamicResource ComboBoxStyle}" SelectionChanged="status_SelectionChanged" Height="auto" Width="Auto">
<ComboBox.BorderBrush>
<SolidColorBrush Color="{DynamicResource Color1}"/>
</ComboBox.BorderBrush>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
With the method FindName(string) I am trying to refer to the ComboBox with its associated name:
ComboBox stcom
{
get
{
return (ComboBox)FindName("stcom");
}
}
if (stcom != null)
{
stcom.ItemsSource = list;
}
But obviously the control can not be found because the reference stcom remains null.
The question now is how to refer to my ComboBox using its name property ?
The answer is:
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Grid>
<TextBlock Name="tbUserIcon" Text="t1" />
<TextBlock Name="tbCheck" Text="✓" />
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and C#:
checkBox.ApplyTemplate();
var tbUserIcon= (TextBlock)checkBox.Template.FindName("tbUserIcon", checkBox);
don't forget the checkBox.ApplyTemplate() be fore Template.FindName() it's important!
First you have to get access to the control template which it has been applied to, then you can find an element of the template by name.
Have a look at the MSDN knowledge base :
How to: Find ControlTemplate-Generated Elements
You can't access controls that are part of a DataTemplate with their name.
You can try to read about some workarounds for example
WPF - Find a Control from DataTemplate in WPF
You can also have a look at the dozens of posts here on SO issuing this topic for example
here
here
here
here
here
here
here
here

How to select first item in expanded group (listview)

Can anyone help me with this problem (c# wpf):
I have a ListView with this Style for my Expander (for each group):
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="False">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
When the user expands the Expander, I would like to select the first item in the expanded group.
I added my group like this (CustomerOrderList = ListView):
CustomerOrderList.ItemsSource = OrderDetails.DefaultView;
CollectionView cv = (CollectionView)CollectionViewSource.GetDefaultView(CustomerOrderList.ItemsSource);
PropertyGroupDescription pgd = new PropertyGroupDescription("OrderInfo");
cv.GroupDescriptions.Add(pgd);
Is this possible?
Thanks,
Senne
Yes it is possible.
Include Linq namespace
using System.Linq;
Handle the Expander's Expanded event
<Expander Expanded="GroupExpander_Expanded" IsExpanded="False" ... />
Code Behind ...
private void GroupExpander_Expanded(object sender, RoutedEventArgs e)
{
var expander = sender as Expander;
//Extract the group
var groupItem = expander.DataContext as CollectionViewGroup;
//Set the first item from the group to ListBox's Selected Item property.
CustomerOrderList.SelectedItem = groupItem.Items.First();
}
If you are using MVVM then use the Attached Property behavior to wrap this functionality into it.
Hope this helps,

Categories