I have a WPF form with a textbox which is defined in xaml file as follows:
<TextBox Grid.Column="1" Grid.Row="9" TabIndex="0" x:Name="txtboxExample" Width="170" >
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding ToolDataContext.ItemInstance.IsToShow, Mode=TwoWay}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
<TextBox.Text>
<Binding Path="ToolDataContext.ItemInstance.UserText" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>
...
<Button Click="someBtn_Click" Content="{x:Static res:Strings.ButtonString}" Name="someButton">
on the xaml.cs file I have the following code:
private void someBtn_Click(object sender, RoutedEventArgs e)
{
...
ToolDataContext.ItemInstance.IsToShow = true;
...
}
In the Item class I have the following code for the property IsToShow:
public class Item : SyncableObject, ISearchableObject, INotifyPropertyChanged
{
...
private bool _isToShow;
public bool IsToShow
{
get { return _isToShow; }
set
{
if (value == _isToShow)
return;
_isToShow = value;
this.OnPropertyChanged("IsToShow");
}
}
...
new public event PropertyChangedEventHandler PropertyChanged;
new public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
...
}
I would expect the window to show the textbox when I click when I on the button.
But it doesn't happen.
Can anyone give me a lead about what am I doing wrong?
Try adding Path to your data trigger binding
<DataTrigger Binding="{Binding Path=ToolDataContext.ItemInstance.IsToShow, Mode=TwoWay}" Value="True">
<DataTrigger Binding="{Binding ToolDataContext.ItemInstance.IsToShow, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
Assuming that you have assigned the datacontext, you need to add UpdateSourceTrigger=PropertyChanged
Related
i have a boolean property and i want to binding it to datatrigger
but my codes not work
i tried this:
public event PropertyChangedEventHandler PropertyChanged;
private bool _IsExist;
public bool IsExist
{
get
{
return _IsExist;
}
set
{
_IsExist = value;
NotifyPropertyChanged("IsExist");
}
}
private void NotifyPropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
and this way i can add items to datagrid and check if mypath exist or not so i need change property based on mypath exist or not
foreach (var i in parsedValues)
{
if (Directory.Exists(MyPath)
{
IsExist = true;
}
else
{
IsExist = false;
}
datagrid.Items.Add(i);
}
and this is my xaml
<DataGridTemplateColumn Header="دانلود">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="Button_Click">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Content" Value="دانلود"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsExist}" Value="True">
<Setter Property="Content" Value="مشاهده"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
DataGridTemplateColumn.CellTemplate looks for binding path inside of each item. So if your windows has the property, you simply can't access it like Binding="{Binding IsExist}". This will only look into the DataContext of each item from the ItemsSource of the DataGrid.
You need to tell XAML to look for the path in the Window not the cell:
Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=IsExist}"
This way, it goes up in the hierarchy until it reaches the first element with the type of Window and looks there for the given path.
I would be so greatful if you could help meee, thx!
HERE IS THE XAML
<ComboBox Margin="8" Name="cmbox" SelectionChanged="cmbox_SelectionChanged" >
<ComboBoxItem IsSelected="True">ESCALONADO</ComboBoxItem>
<ComboBoxItem>INTEGRAL</ComboBoxItem>
</ComboBox>
<TextBox IsReadOnly="{Binding Testcmb}" Grid.Column="1" Margin="8"/>
HERE IS A LITTLE BIT OF THE CODE BEHIND
I tried to attribute the value of the property Testcmb based on the selected item on the combobox, and then make the bindin to the textbox to turn it as a IsReadOnly="true". Is the sintax right?
private void cmbox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(cmbox.SelectedIndex > 0)
{
(Object).Testcmb = true;
}
else
{
(Object).Testcmb = false;
}
}
private bool _testcmb;
public bool Testcmb
{
get { return _testcmb; }
set
{
if (this._testcmb != value)
{
this._testcmb = value;
this.NotifyPropertyChanged("Testcmb");
};
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
Welcome to StackOverflow. Your syntax is indeed correct, however you are mixing data binding with event handlers and all of this within view's code-behind.
You can do what you want using Style which is more clear for this kind of UI logic, as for me. Here is XAML-only solution:
<ComboBox x:Name="cbox">
<ComboBoxItem IsSelected="True" Content="ESCALONADO"/>
<ComboBoxItem Content="INTEGRAL" />
</ComboBox>
<TextBox Text="Some text...">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedIndex, ElementName=cbox}" Value="0">
<Setter Property="IsReadOnly" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
I have the following XAML which should expand my whole treeview when a specific property ExpandNodes is True, but it is never triggered.
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding ExpandNodes}" Value="True">
<Setter Property="IsExpanded" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding ExpandNodes}" Value="False">
<Setter Property="IsExpanded" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
// some other code
</TreeView>
In my ViewModel I set ExpandNodes to True during a specific event, yet the treeview remains non expanded. It's not an issue with my DataContext as I have other properties from the same Viewmodel that are bound and work fine.
My Viewmodel:
private bool _expandnodes;
public bool ExpandNodes
{
get
{
return _expandnodes;
}
set
{
_expandnodes = value;
OnPropertyChanged("ExpandNodes");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string PropName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropName));
}
}
Too compliacted, you can simply bind IsExpanded property to your object and raise PropertyChanged event.
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding ExpandNodes,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
TargetNullValue=False}" />
</Style>
</TreeView.ItemContainerStyle>
// some other code
</TreeView>
I have an image that need to be showed based on condition, is that attachment file or not. The problem is, I've set trigger that set the value of the condition, but seems like the condition isn't work and the value always set to true.
<Image
Width="30"
Height="30"
Source="Resources/Images/chat_file_attach.png">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding AttachStat}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding AttachStat}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
The question is. Is there any way to make the default value to false? I've set it to true on the C# looping data, whenever the condition is attachment included.
Take a look in your output window and search for:
System.Windows.Data Warning: 40 : BindingExpression path error
I think the AttachStat property is not available in the image's DataContext.
Use a single DataTrigger and make sure that the DataContext of the Image has a public AttachStat property:
<Image x:Name="img" Width="30" Height="30" Source="Resources/Images/chat_file_attach.png">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding AttachStat}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
img.DataContext = new YourClass();
...
public class YourClass : INotifyPropertyChanged
{
private bool _attachStat;
public bool AttachStat
{
get
{
return _attachStat;
}
set
{
_attachStat = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
You can use a BoolToVisibilityConverter to convert a Boolean to and from a Visibility value.
In the resource section:
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
And the image:
<Image Width="30"
Height="30"
Source="Resources/Images/chat_file_attach.png"
Visibility="{Binding AttachStat,
Converter={StaticResource BoolToVisibilityConverter}}" />
Created DataGrid and set CanUserAddRows="True"
Have a button which saves updates in the cs file:
private void Save_Click(object sender, RoutedEventArgs e)
{
UnitService unitService = new UnitService();
unitService.SaveUpdates(valuationCase);
MainWindow mainWin = new MainWindow();
mainWin.Show();
this.Close();
}
There is also a textbox not in the datagrid on the window which is editable and this is correctly saving edits with the save click button. Just the new rows aren't.
Any ideas??
datagrid definition:
<DataGrid Name="dgCommentsList" AutoGenerateColumns="False" Margin="10,196,9.953,38.204" CanUserAddRows="True" FontSize="18">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="bold" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="Type" Text="{Binding Type}" >
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsReadOnly}" Value="False">
<Setter Property="TextBox.IsReadOnly" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsReadOnly}" Value="True">
<Setter Property="TextBox.IsReadOnly" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
I think you need to set the mode of the binding for it to write back to the underlying object.Plus I noticed your DataGrid does not have an ItemsSource. I'm guessing as this was just a snippet that you left it out.
<TextBox x:Name="Type" Text="{Binding Type, Mode=TwoWay}">
You should commit the edit on the row using dataGrid.CommitEdit()
Edit: After diagnosing the issue here goes
You either need to implement INotifyPropertyChanged on your DataContext class (i.e: Viewmodel) like so:
public class ViewModel: INotifyPropertyChanged
{
private string _type;
public string Type
{
get { return _type; }
set
{
_type = value;
OnPropertyChanged("Type");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Or you extend from DependencyObject and use Dependency Properties, like so:
public class ViewModel: DependencyObject
{
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register(
"Type", typeof (string), typeof (ViewModel), new PropertyMetadata(default(string)));
public int Type
{
get { return (int) GetValue(TypeProperty ); }
set { SetValue(TypeProperty , value); }
}
}
Hope it helps ;)