I've following code in my WPF app.I'm trying to set the focus on a textbox on a button click...i.e. on invoking Check() method...
Code:
MainWindowResources.xaml
<Style TargetType="TextBox" x:Key="MyFiedlStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=FocusOnMyField}" Value="true">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=myField}"/>
</DataTrigger>
</Style.Triggers>
</Style>
MainWindow.xaml
<TextBox HorizontalAlignment="Left" Margin="1,1,0,0" Width="180" Text="{Binding MyAttributes.MyFieldValue}" TabIndex="4" Grid.Row="3" VerticalAlignment="Top" Grid.Column="5"
Name="myField" Style="{DynamicResource MyFieldStyle}"/>
MainWindowViewModel
private bool FocusOnMyField
{
get { return m_FocusOnMyField; }
set
{
m_FocusOnMyField = value;
OnPropertyChanged("FocusOnMyField");
}
}
private void Check()
{
this.FocusOnSecDescription = true;
}
Thanks.
Related
I have a problem in a WPF .NET Core 3.1 that I am writing.
There is a 'Main Page', where the user can input some filters that will be used to search for some files by an external webAPI; so far so good. The response from the webAPI is an XML with the list of the files available and the user must choose which of these files download. To do so, I have a 'popup box' where the user can read all the available files and selected the desired ones by checkboxes. I have to add some buttons to select / deselect all the files and here lies the problem: the files are selected but the fronted does not notice and keep showing them as unchecked.
In the main page, parsing the XML I generate a List of these objects:
public class righeNoteSpese {
public Boolean selezionato { get; set; }
public Boolean isOK { get; set; }
public String errore { get; set; }
// Other String fields...
public righeNoteSpese() {
selezionato = false;
isOK = true;
errore = String.Empty;
}
}
and I call the popup with
ListaXML l = new ListaXML(lr);
await this.ShowChildWindowAsync(l.listaXML);
where lr is the list of rows I found.
The code behind of the popup is
public partial class ListaXML : ChildWindow
{
public List<righeNoteSpese> Elenco = new List<righeNoteSpese>();
public ListaXML()
{
InitializeComponent();
}
public ListaXML(List<righeNoteSpese> listF) {
InitializeComponent();
this.DataContext = this;
Elenco = listF;
selFiles.ItemsSource = listF;
/* If not commented the foreach works and all the rows are checked!
foreach (righeNoteSpese r in Elenco)
{
if (r.isOK)
{
r.selezionato = true;
}
}*/
}
private void All_Click(object sender, RoutedEventArgs e)
{
foreach (righeNoteSpese r in Elenco) {
if (r.isOK)
{
r.selezionato = true;
}
}
}
}
The XAML of the popup is
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Name="Btn1" Width="100" Content="Select All" Grid.Row="0" Grid.Column="0" Margin="10 15 10 15" Click="All_Click" />
<DataGrid Name="selFiles" AutoGenerateColumns="False" CanUserAddRows="false" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Auto" AlternatingRowBackground="LightGray" Grid.Row="1" Grid.ColumnSpan="4">
<DataGrid.Columns><DataGridTextColumn Header="Errore" Width="200" Binding="{Binding errore, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding isOK}" Value="False">
<Setter Property="Background" Value="Red"/>
<Setter Property="FontStyle" Value="Italic" />
</DataTrigger>
<DataTrigger Binding="{Binding selezionato}" Value="True">
<Setter Property="Background" Value="SpringGreen"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Width="SizeToHeader" IsReadOnly="True" Header="Select">
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding isOK}" Value="False">
<Setter Property="Background" Value="Red"/>
<Setter Property="FontStyle" Value="Italic" />
</DataTrigger>
<DataTrigger Binding="{Binding selezionato}" Value="True">
<Setter Property="Background" Value="SpringGreen"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding selezionato, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="2,0,2,0" IsEnabled="{Binding isOK, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Other columns... -->
</DataGrid.Columns>
</DataGrid>
</Grid>
If I check manually a checkbox everything works, the background changes and the change is passed back to the main page. If I use the button the values are changed and passed back to the main page but there is no change in the frontend but if I execute these same instructions when I call the page everything is OK.
What am I missing?
Thank you for your help.
I didn't implement correctly the INotifyPropertyChanged, I changed the class from
public Boolean selezionato { get; set; }
to
private Boolean _selezionato;
public Boolean selezionato {
get {
return _selezionato;
}
set {
_selezionato = value;
OnPropertyChanged("selezionato");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
and now it works fine.
In WPF I'm trying to create a "flag" control that displays a checkmark or an X based on a bound dependency property (Flag)
<UserControl x:Name="Root" (Other user control stuff)>
<ContentControl Height="20" x:Name="flagHolder">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Root, Path=Flag}" Value="False">
<Setter Property="Content" Value="{StaticResource XIcon}" />
<Setter Property="Foreground" Value="Crimson"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Root, Path=Flag}" Value="True">
<Setter Property="Content" Value="{StaticResource CheckIcon}" />
<Setter Property="Foreground" Value="ForestGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</UserControl>
On startup every icon is correct (I have several of these controls, each bound to different values). However, when I toggle a few (one that was "off" turns "on" and the one currently "on" turns "off") I see two things:
The control that was turned "on" has become a green check (as desired)
The control that was turned "off" is now just blank
Inspecting the visual tree seems to indicate that everything is working (though I could easily be missing something here), and the order of the triggers doesn't seem to matter. What am I doing wrong?
Here is an example icon, the path geometry is removed since its just noise:
<Viewbox x:Key="CheckIcon" x:Shared="False">
<Path Style="{StaticResource IconPathStyle}">
<Path.Data>
<PathGeometry Figures="Bunch of SVG" FillRule="NonZero"/>
</Path.Data>
</Path>
</Viewbox>
I'm unable to reproduce your issue, but here what I have and it's working:
App.xaml
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Viewbox x:Key="CheckIcon" x:Shared="False">
<Canvas Height="24" Width="32">
<Path Width="7.85446" Height="8.57578" Canvas.Left="-0.0522281" Canvas.Top="-0.100391" Stretch="Fill" StrokeThickness="1.04192" StrokeMiterLimit="2.75" Stroke="#FF000000" Data="F1 M 0.468732,4.66838L 3.03345,7.95443L 7.28127,0.420569"/>
</Canvas>
</Viewbox>
<Viewbox x:Key="XIcon" x:Shared="False">
<Canvas Height="24" Width="32">
<Path Data="M0,0 L1,1 M0,1 L1,0" Stretch="Fill" Stroke="Black" StrokeThickness="3" Width="12" Height="12" />
</Canvas>
</Viewbox>
</Application.Resources>
</Application>
YesNo.xaml
<UserControl x:Class="WpfApplication1.YesNo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="Root">
<ContentControl Height="20" Name="flagHolder">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Root, Path=Flag}" Value="False">
<Setter Property="Content" Value="{StaticResource XIcon}" />
<Setter Property="Foreground" Value="Crimson"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Root, Path=Flag}" Value="True">
<Setter Property="Content" Value="{StaticResource CheckIcon}" />
<Setter Property="Foreground" Value="ForestGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</UserControl>
YesNo.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class YesNo : UserControl
{
public YesNo()
{
InitializeComponent();
}
public static readonly DependencyProperty FlagProperty = DependencyProperty.Register(
"Flag", typeof(bool), typeof(YesNo), new PropertyMetadata(default(bool)));
public bool Flag {
get {
return (bool) GetValue(FlagProperty);
}
set {
SetValue(FlagProperty, value);
}
}
}
}
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:wpfApplication1="clr-namespace:WpfApplication1"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Title="" Width="400" Height="400">
<StackPanel Orientation="Vertical" Margin="50">
<wpfApplication1:YesNo Flag="{Binding Flag1}"/>
<wpfApplication1:YesNo Flag="{Binding Flag2}"/>
<wpfApplication1:YesNo Flag="{Binding Flag2}"/>
<wpfApplication1:YesNo Flag="{Binding Flag1}"/>
<Button Content="Toggle" Click="ButtonBase_OnClick"></Button>
</StackPanel>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : INotifyPropertyChanged
{
private bool _flag1;
private bool _flag2;
public MainWindow()
{
InitializeComponent();
DataContext = this;
Flag1 = true;
Flag2 = false;
}
public bool Flag1 {
get {
return _flag1;
}
set {
_flag1 = value;
OnPropertyChanged();
}
}
public bool Flag2 {
get {
return _flag2;
}
set {
_flag2 = value;
OnPropertyChanged();
}
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) {
Flag1 = !Flag1;
Flag2 = !Flag2;
}
}
How it looks like:
Video: http://www.screencast.com/t/J5IY7DR3Ry
I've created ControlTemplates:
<Window.Resources>
<ControlTemplate x:Key="imgNo" TargetType="{x:Type Control}">
<Image Source="pack://application:,,,/Images/up.png"/>
</ControlTemplate>
<ControlTemplate x:Key="imgUp" TargetType="{x:Type Control}">
<!--<TextBlock Text="Up"/>-->
<Image Source="pack://application:,,,/Images/up.png"/>
</ControlTemplate>
<ControlTemplate x:Key="imgDown" TargetType="{x:Type Control}">
<Image Source="pack://application:,,,/Images/downArrow.png"/>
</ControlTemplate>
<DataTemplate x:Key="ButtonOneDataTemplate">
<Control x:Name="theControl" Template="{DynamicResource imgNo}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsImageChanged}" Value="true">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgUp}" />
</DataTrigger>
<DataTrigger Binding="{Binding IsImageChanged}" Value="false">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgDown}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</WindowResources>
and Button in DataGrid which uses above ControlTemplates:
<DataGrid ItemsSource="{Binding Persons}" Grid.Row="1" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding IdPerson}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<Border Background="Violet">
<StackPanel>
<Button ContentTemplate="{StaticResource ButtonOneDataTemplate}"
Command="{Binding DataContext.HelloCommand, RelativeSource=
{RelativeSource AncestorType=Window}}"
CommandParameter="{Binding DataContext.Hello,
RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
My ViewModel:
public class MainWindowViewModel:ViewModelBase
{
public RelayCommand HelloCommand { get; set; }
public MainWindowViewModel()
{
LoadPersons();
HelloCommand = new RelayCommand(SayHello);
}
int helloCounter = 0;
private void SayHello(object obj)
{
if (helloCounter % 2 == 0)
IsImageChanged = true;
else
IsImageChanged = false;
helloCounter++;
}
private bool isImageChanged=true;
public bool IsImageChanged
{
get { return isImageChanged; }
set { isImageChanged = value;
OnPropertyChanged("IsImageChanged");
}
}
}
What I want is when I click on the button <Button ContentTemplate="{StaticResource ButtonOneDataTemplate}"/>, then Template should be replaced to {DynamicResource imgDown} or {DynamicResource imgUp}. DataTrigger depends on IsImageChanged value.
However, if I click on the Button, then DataTrigger is not fired(Controltemplates such as imgUp, imgDown are not changed). How can I achieve this from my ViewModel?
Problem is that DataGrid column is not a part of a visual tree, and because of that it does not inherit DataContext. To be able to use DataTriggers in your ButtonOneDataTemplate you need that button, you applying this template to, has correct DataContext. There is a trick, how to provide DataContext to elements that are not in VisualTree, described here
Applying that solution to your code we'll have the following:
Proxy
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
Window.Resources
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
<DataTemplate x:Key="ButtonOneDataTemplate">
<Control x:Name="theControl" Template="{DynamicResource imgNo}" Foreground="Orange"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.IsImageChanged}" Value="True">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgUp}" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.IsImageChanged}" Value="False">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgDown}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
HeaderTemplate
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<Border Background="Violet">
<StackPanel>
<Button ContentTemplate="{StaticResource ButtonOneDataTemplate}"
DataContext="{Binding Path=Data, Source={StaticResource proxy}}"
Command="{Binding DataContext.ButtonClick, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
I want when I press on bulb button every time picture will change. I tried but without success. My code doesn't work, please tell my why, thanks.
Here is the UserControl in XAML:
<UserControl x:Class="PL_Wpf.CustomControls.Bulb"
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:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
>
<Grid>
<Button x:Name="BulbButton" Height="60" Width="40" Click="BulbButton_Click" >
<Button.Template>
<ControlTemplate>
<Image Source="../Pics/bulb_off.jpg" Width="40" Height="60" >
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Bulb, Path=OnOff}" Value="True">
<Setter Property="Source" Value="../Pics/bulb_on.jpg" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Bulb, Path=OnOff}" Value="False">
<Setter Property="Source" Value="../Pics/bulb_off.jpg" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</UserControl>
And here is the code behind:
public partial class Bulb : UserControl, INotifyPropertyChanged
{
public bool OnOff { get; set; }
public Bulb()
{
InitializeComponent();
DataContext = this;
OnOff = false;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
public void BulbButton_Click(object sender, RoutedEventArgs e)
{
OnOff = (OnOff == false) ? true : false;
}
public bool On
{
get { return OnOff; }
set
{
OnOff = value;
OnPropertyChanged(new PropertyChangedEventArgs("On"));
}
}
}
The think that you want to achieve with your control can be simply done by modifying the control template of a checkbox.
Just add this code in the window in place of your control:
<CheckBox>
<CheckBox.Template>
<ControlTemplate TargetType="CheckBox">
<Grid>
<Image Source="pack://siteoforigin:,,,/Pics/bulb_off.jpg" Width="40" Height="60" />
<Image Source="pack://siteoforigin:,,,/Pics/bulb_on.jpg" Width="40" Height="60" Name="CheckMark" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="CheckMark" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</CheckBox.Template>
</CheckBox>
I am trying to disable ValidatesOnDataErrors on a TextBox if a certain checkbox is checked.
I have tried placing a trigger on textbox to enable or disable validation based on the checkbox seems like the trigger gets hit but does not disable validation. I am using IDataErrorInfo for validation in the .cs code. Here is the code I have tried, this has been a headache so hope you can help.
.xaml
<TextBox Name="txtFoundERTReading" Height="23" Canvas.Left="125" TextWrapping="Wrap" Canvas.Top="136" Width="120">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cbFoundERTReading, Path=IsChecked}" Value="False">
<Setter Property="Text" Value="{Binding Found.ERTReading, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=cbFoundERTReading, Path=IsChecked}" Value="True">
<Setter Property="TextBox.IsEnabled" Value="False" />
<Setter Property="Text" Value="{Binding Found.ERTReading, Mode=TwoWay, ValidatesOnDataErrors=False, UpdateSourceTrigger=PropertyChanged}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Instead of changing the ValidatesOnDataErrors property at run time, the best approach is to have a boolean property in viewmodel and do validation only if it is true. The boolean property can bound to IsChecked property of a Checkbox.
public string Name
{
get { return name; }
set { name = value; RaisePropertyChanged("Name"); }
}
public string this[string columnName]
{
get
{
if (CanValidate)
{
if (columnName == "Name")
{
if (!ValidateName())
{
return "Error";
}
}
}
return "";
}
}
private bool canValidate;
public bool CanValidate
{
get { return canValidate; }
set { canValidate = value; RaisePropertyChanged("CanValidate"); RaisePropertyChanged("Name");}
}
private bool ValidateName()
{
if (String.IsNullOrEmpty(Name))
{
return false;
}
return true;
}
The XAML looks like below,
<StackPanel>
<TextBox Margin="5" Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}"/>
<CheckBox Margin="5" Content="Can validate" IsChecked="{Binding CanValidate, Mode=TwoWay}"/>
</StackPanel>
Use this,
Validation.ErrorTemplate="{x:Null}"